Suspense 异步组件 | 源码解析系列 5.8
一,引言
Suspense是Vue3新增的内置组件,用于处理异步组件的加载状态。它允许开发者优雅地处理异步组件的loading、error和ready状态,提供更好的用户体验。本文将深入解析Vue3中Suspense的实现原理,包括异步组件的识别、加载状态管理、fallback渲染等方面。
二、Suspense概述
2.1 什么是Suspense
Suspense是一个特殊的组件,它可以等待其嵌套的异步组件加载完成后,再渲染默认内容。
<template> <Suspense> <template #default> <AsyncComponent /> </template> <template #fallback> <LoadingSpinner /> </template> </Suspense> </template>2.2 使用场景
Suspense主要用于以下场景:异步组件加载、网络请求等待、动态导入组件、异步setup函数。
三、异步组件
3.1 defineAsyncComponent
异步组件通过defineAsyncComponent定义。
import{defineAsyncComponent}from'vue'constAsyncComponent=defineAsyncComponent(()=>import('./AsyncComponent.vue'))3.2 异步组件选项
defineAsyncComponent({loader:()=>import('./AsyncComponent.vue'),loadingComponent:LoadingComponent,errorComponent:ErrorComponent,delay:200,timeout:3000,retry:3})3.3 async setup
setup可以是异步函数。
exportdefault{asyncsetup(){constdata=awaitfetchData()return{data}}}四、Suspense实现
4.1 Suspense组件定义
// packages/runtime-core/src/components/Suspense.tsexportconstSuspense={__isSuspense:true,process(n1:SuspenseVNode,n2:SuspenseVNode,container:HostElement,anchor:HostNode|null,parentComponent:ComponentInternalInstance,parentSuspense:SuspenseBoundary|null,isSVG:boolean,optimized:boolean):void{// 处理Suspense挂载和更新}}4.2 SuspenseVNode结构
// Suspense VNodeinterfaceSuspenseVNode{type:typeofSuspense props:{timeout?:number}children:{default:VNode fallback:VNode}}五、加载状态管理
5.1 Suspense状态
// Suspense内部状态interfaceSuspenseState{isLoading:booleanerror:Error|nullresolve:()=>voidpromise:Promise<void>|null}5.2 状态转换
// 状态转换// pending -> resolved -> pending// -> rejected六、异步依赖处理
6.1 依赖收集
Suspense收集所有异步依赖。
// 收集异步依赖functionresolveAsyncDependencies(comp:Component,parent:ComponentInternalInstance):Promise<any>{constpromises:Promise<any>[]=[]// 收集异步组件collectAsyncComponents(comp,promises)// 等待所有异步依赖returnPromise.all(promises)}6.2 Promise处理
// 处理PromisefunctionsetupSuspense(comp:Component,parent:ComponentInternalInstance):SuspenseState{conststate:SuspenseState={isLoading:true,error:null,resolve:null,promise:null}state.promise=newPromise((resolve)=>{state.resolve=resolve})// 执行setup或加载异步组件execWithSuspense(comp,parent,state)returnstate}七、fallback渲染
7.1 fallback内容
fallback在异步内容加载时显示。
// 渲染fallbackfunctionrenderFallbackContent(suspense:SuspenseState):VNode{if(suspense.isLoading){// 渲染fallbackreturnsuspense.fallbackVNode}}7.2 切换时机
// 切换到默认内容functionresolveSuspense(suspense:SuspenseState):void{suspense.isLoading=falseif(suspense.resolve){suspense.resolve()}}八、错误处理
8.1 错误边界
// 错误处理functionhandleAsyncError(error:Error,suspense:SuspenseState):void{suspense.isLoading=falsesuspense.error=errorif(suspense.reject){suspense.reject(error)}}8.2 errorComponent
可以使用errorComponent显示错误状态。
// errorComponent处理defineAsyncComponent({loader:()=>import('./Async.vue'),errorComponent:ErrorComponent})九、使用示例
9.1 基础用法
<template> <Suspense> <template #default> <AsyncComponent /> </template> <template #fallback> <LoadingSpinner /> </template> </Suspense> </template>9.2 多个异步组件
<template> <Suspense> <template #default> <div> <AsyncComponent1 /> <AsyncComponent2 /> </div> </template> <template #fallback> <Loading /> </template> </Suspense> </template>9.3 async setup
exportdefault{asyncsetup(){constuser=awaitfetchUser()return{user}}}十、嵌套Suspense
10.1 多层Suspense
Suspense可以嵌套使用。
<Suspense> <template #default> <ParentAsync /> </template> <template #fallback> <Loading /> </template> </Suspense> <!-- ParentAsync内部 --> <Suspense> <template #default> <ChildAsync /> </template> <template #fallback> <ChildLoading /> </template> </Suspense>十一、总结
本文深入解析了Vue3中Suspense异步组件的实现原理。Suspense通过收集异步依赖、管理加载状态、渲染fallback内容等机制,优雅地处理了异步组件的加载过程。它可以与defineAsyncComponent和async setup配合使用,提供更好的异步编程体验。
参考资料
- Vue3 官方源码:https://github.com/vuejs/core
- Vue3 Suspense:packages/runtime-core/src/components/Suspense.ts