0Pricing
Vue Academy · Урок

Компонент Vue Suspense

со слотами default и #fallback, загрузка асинхронных компонентов и вложенный Suspense

«Компонент Vue Suspense» — бесплатный урок Vue Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Vue Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Vue Academy содержит 4 уроков всего.

Что решает Suspense

Suspense — встроенный компонент Vue, который координирует состояния загрузки компонентов с асинхронными зависимостями.

Без него каждый асинхронный компонент самостоятельно управляет индикатором загрузки. С Suspense вы объявляете одну границу, которая ожидает завершения всей вложенной асинхронной работы и показывает единый fallback, пока всё не будет готово.

Два слота: default и fallback

Suspense предоставляет два именованных слота:

  • default — настоящее содержимое, которое может включать асинхронные компоненты или асинхронный setup()
  • fallback — содержимое, отображаемое, пока разрешается слот default

Когда все асинхронные зависимости завершаются, Vue заменяет fallback содержимым default.

<template>
  <Suspense>
    <template #default>
      <UserDashboard />
    </template>
    <template #fallback>
      <div class="spinner">Loading dashboard...</div>
    </template>
  </Suspense>
</template>

Асинхронный setup() как зависимость

Компонент становится асинхронной зависимостью, когда его функция setup() объявлена как async и ожидает результат. Vue отслеживает возвращаемое обещание.

Эквивалентом <script setup> является непосредственное использование await верхнего уровня внутри блока.

<script setup>
import { ref } from 'vue'

// Top-level await makes this an async dependency of Suspense
const res = await fetch('/api/profile')
const profile = ref(await res.json())
</script>

<template>
  <h1>Welcome, {{ profile.name }}</h1>
</template>

Асинхронные компоненты тоже учитываются

Компоненты, созданные с помощью defineAsyncComponent, также отслеживаются компонентом Suspense. fallback остаётся видимым, пока не завершится динамический import().

Это позволяет разделять тяжёлые компоненты на отдельные части без написания отдельного интерфейса загрузки для каждого компонента.

<script setup>
import { defineAsyncComponent } from 'vue'

const Chart = defineAsyncComponent(() =>
  import('./HeavyChart.vue')
)
</script>

<template>
  <Suspense>
    <Chart />
    <template #fallback>Preparing chart...</template>
  </Suspense>
</template>

Совместное ожидание нескольких асинхронных дочерних компонентов

Если слот по умолчанию содержит несколько асинхронных зависимостей, Suspense ждёт, пока все они не будут готовы, прежде чем показать содержимое.

Это предотвращает скачки макета, когда компоненты появляются по одному.

<template>
  <Suspense>
    <div>
      <UserStats />   <!-- async setup -->
      <RecentOrders /> <!-- async setup -->
      <Recommendations /> <!-- async component -->
    </div>
    <template #fallback>
      <PageSkeleton />
    </template>
  </Suspense>
</template>

Перехват отклонений с помощью onErrorCaptured

Если асинхронный setup() завершается ошибкой (например, из-за неудачного запроса), ошибка передаётся ближайшему хуку onErrorCaptured в родительском компоненте.

Сам Suspense не отображает ошибки, поэтому его используют вместе с границей ошибок.

<script setup>
import { ref, onErrorCaptured } from 'vue'

const error = ref(null)

onErrorCaptured((err) => {
  error.value = err
  return false // stop the error from propagating further
})
</script>

Шаблон «граница ошибок + Suspense»

В распространённом рабочем шаблоне Suspense помещают внутрь компонента-границы ошибок. onErrorCaptured возвращает false, чтобы остановить распространение ошибки и вместо этого отобразить интерфейс ошибки.

<script setup>
import { ref, onErrorCaptured } from 'vue'
const err = ref(null)
onErrorCaptured((e) => { err.value = e; return false })
</script>

<template>
  <p v-if="err">Failed to load: {{ err.message }}</p>
  <Suspense v-else>
    <ProfilePanel />
    <template #fallback>Loading...</template>
  </Suspense>
</template>

События ожидания и завершения

Suspense создаёт события жизненного цикла, которые можно отслеживать:

  • @pending — срабатывает при переходе в состояние ожидания (загрузки)
  • @resolve — срабатывает после завершения разрешения слота по умолчанию
  • @fallback — срабатывает при отображении резервного содержимого

Это полезно для аналитики или индикаторов прогресса.

<template>
  <Suspense @pending="onPending" @resolve="onResolve">
    <RouteView />
    <template #fallback>Loading route...</template>
  </Suspense>
</template>

Свойство для отложенного резервного содержимого

Свойство timeout (в миллисекундах) откладывает показ резервного содержимого. Если асинхронная операция завершается быстрее заданного времени, резервное содержимое не появляется.

Это предотвращает краткое появление индикатора загрузки при быстрых ответах.

<template>
  <!-- Only show fallback if loading exceeds 200ms -->
  <Suspense :timeout="200">
    <FastPanel />
    <template #fallback>Loading...</template>
  </Suspense>
</template>

Suspense с маршрутизацией и переходами

Suspense сочетается с RouterView и Transition, позволяя анимировать асинхронные переходы между маршрутами. Порядок важен: Transition оборачивает Suspense, а тот, в свою очередь, — компонент маршрута.

<template>
  <RouterView v-slot="{ Component }">
    <Transition mode="out-in">
      <Suspense>
        <component :is="Component" />
        <template #fallback>Loading page...</template>
      </Suspense>
    </Transition>
  </RouterView>
</template>

Когда НЕ следует использовать Suspense

Не используйте Suspense для данных, которые часто загружаются заново, пока компонент остаётся смонтированным: он управляет только первоначальным разрешением асинхронных зависимостей. Для текущих состояний загрузки (постраничной загрузки, повторного запроса) вместо этого используйте обычную реактивную ссылку loading.

<script setup>
import { ref } from 'vue'
const loading = ref(false)
async function loadMore() {
  loading.value = true
  await fetchNextPage()
  loading.value = false
}
</script>

Быстрая проверка

Проверьте своё понимание Suspense.

Повторение

Вы узнали, как Suspense координирует асинхронные зависимости:

  • слот по умолчанию содержит асинхронное содержимое (асинхронный setup или асинхронные компоненты)
  • резервный слот отображается во время загрузки
  • Компонент ждёт завершения работы всех асинхронных дочерних компонентов, прежде чем показать содержимое
  • Отклонения передаются в onErrorCaptured родительской границе ошибок
  • timeout предотвращает краткое появление индикатора загрузки, а события вроде @resolve помогают аналитике

Часто задаваемые вопросы

Урок «Компонент Vue Suspense» бесплатный?

Да — полный текст урока «Компонент Vue Suspense» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Vue Academy, подпишись на CoddyKit PRO. Курс Vue Academy содержит 4 уроков всего.

Чему я научусь в уроке «Компонент Vue Suspense»?

со слотами default и #fallback, загрузка асинхронных компонентов и вложенный Suspense Ты практикуешь Vue Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Vue Academy?

Предыдущий опыт не требуется. Vue Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.

Сколько времени занимает урок «Компонент Vue Suspense»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Vue Academy?

Да. Каждый урок Vue Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Компонент Vue Suspense
  2. Асинхронные компоненты с defineAsyncComponent
  3. Потоковый SSR с renderToWebStream
  4. Стратегии отложенной гидратации
← Назад к Vue Academy