Асинхронні компоненти та затримка в Vue.js
Асинхронні компоненти
Асинхронні компоненти завантажуються за запитом (ліниве завантаження), що зменшує початковий розмір пакету. Vue надає defineAsyncComponent для цієї мети.
defineAsyncComponent
import { defineAsyncComponent } from 'vue'
// Основний асинхронний компонент
const AsyncModal = defineAsyncComponent(
() => import('./components/HeavyModal.vue')
)
// З параметрами
const AsyncDashboard = defineAsyncComponent({
loader: () => import('./components/Dashboard.vue'),
loadingComponent: LoadingSpinner,
errorComponent: ErrorDisplay,
delay: 200, // Затримка перед показом завантаження (мс)
timeout: 10000, // Таймаут перед показом помилки (мс)
})<template>
<!-- Завантажується лише під час рендерингу -->
<AsyncModal v-if="showModal" />
<AsyncDashboard />
</template>Suspense
<Suspense> — вбудований компонент для обробки асинхронних залежностей — він показує резервний контент, поки асинхронні компоненти або асинхронна ініціалізація завантажуються.
<template>
<Suspense>
<!-- Слот за замовчуванням: асинхронний контент -->
<template #default>
<AsyncDashboard />
</template>
<!-- Резервний слот: показується під час завантаження -->
<template #fallback>
<LoadingSpinner />
</template>
</Suspense>
</template>Асинхронна ініціалізація
Компоненти з асинхронною setup працюють з <Suspense>:
<!-- UserProfile.vue -->
<script setup>
// Це робить компонент асинхронним — потрібен батьківський Suspense
const response = await fetch('/api/user/1')
const user = await response.json()
</script>
<template>
<div>
<h1>{{ user.name }}</h1>
<p>{{ user.email }}</p>
</div>
</template><!-- Parent.vue -->
<template>
<Suspense>
<UserProfile />
<template #fallback>
<p>Завантаження користувача...</p>
</template>
</Suspense>
</template>Події Suspense
<Suspense
@pending="onPending"
@resolve="onResolve"
@fallback="onFallback"
>
<AsyncComponent />
<template #fallback>
<LoadingSpinner />
</template>
</Suspense>Вкладений Suspense
<Suspense>
<template #default>
<Dashboard>
<!-- Внутрішній Suspense для незалежного завантаження -->
<Suspense>
<template #default><SlowWidget /></template>
<template #fallback><WidgetSkeleton /></template>
</Suspense>
</Dashboard>
</template>
<template #fallback>
<DashboardSkeleton />
</template>
</Suspense>Комбінування з Vue Router
<template>
<RouterView v-slot="{ Component }">
<Suspense>
<template #default>
<component :is="Component" />
</template>
<template #fallback>
<PageLoading />
</template>
</Suspense>
</RouterView>
</template>Обробка помилок
<script setup>
import { onErrorCaptured, ref } from 'vue'
const error = ref<Error | null>(null)
onErrorCaptured((err) => {
error.value = err
return false // Запобігти поширенню
})
</script>
<template>
<div v-if="error">Помилка: {{ error.message }}</div>
<Suspense v-else>
<AsyncComponent />
<template #fallback><Loading /></template>
</Suspense>
</template>Важливо:
Використовуйте defineAsyncComponent для розподілу коду — завантажуйте важкі компоненти за запитом. Використовуйте <Suspense> для показу станів завантаження для асинхронних компонентів та компонентів з асинхронною setup(). Поєднуйте обидва з Vue Router для розподілу коду на рівні маршруту. Suspense все ще є експериментальним у Vue 3, але широко використовується.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.