--- name: async-components-suspense description: Handle async operations, top-level await, and Suspense boundaries --- # Async Components & Suspense Vue provides patterns for handling asynchronous operations in components. ## Top-Level await in Script Setup ` ``` **Important**: Components with top-level `await` **require a `` boundary** in a parent component, otherwise they won't render. ## Suspense `` is a built-in component for handling async dependencies in the component tree. ```vue ``` ### Suspense Slots - **default**: The async content to render - **fallback**: Content shown while async dependencies are resolving ```vue ``` ## Async Components Define components that are loaded asynchronously: ```ts import { defineAsyncComponent } from 'vue' const AsyncModal = defineAsyncComponent(() => import('./components/Modal.vue') ) // With options const AsyncModalWithOptions = defineAsyncComponent({ loader: () => import('./components/Modal.vue'), loadingComponent: LoadingSpinner, errorComponent: ErrorDisplay, delay: 200, // Delay before showing loading (ms) timeout: 3000 // Timeout before showing error (ms) }) ``` ## Common Async Pitfalls ### Pitfall 1: Missing Suspense Boundary ```vue ``` ### Pitfall 2: Lifecycle Hooks After await Lifecycle hooks must be registered synchronously, before any `await`: ```vue ``` ```vue ``` ### Pitfall 3: Composables After await Composables that use lifecycle hooks must be called before `await`: ```vue ``` ### Pitfall 4: Watchers Created in Async Callbacks Watchers in async callbacks aren't auto-disposed: ```ts // ❌ Memory leak - watcher not auto-disposed setTimeout(() => { watch(source, callback) // Must be stopped manually }, 1000) // ✅ Watchers in setup are auto-disposed watch(source, callback) ``` ## Recommended Pattern: Avoid Top-Level await Often better to handle async in `onMounted` or with watchers: ```vue ``` This pattern: - Doesn't require Suspense - Gives you control over loading/error states - Works everywhere without special parent setup ## When to Use Suspense Use Suspense when: - You have nested async components - You want coordinated loading states across multiple async children - You're doing SSR with async data requirements Avoid Suspense when: - Simple single-component async loading - You need fine-grained control over loading states - You want to avoid Suspense complexity ## Suspense Events ```vue ``` ## Error Handling with Suspense Use `onErrorCaptured` or `` pattern: ```vue ```