Vue中的Suspense原理讲解
文章目录一、 核心原理解析1. 状态机3 种状态与 2 个插槽2. 异步依赖收集机制巧用“Promise 抛出与捕获”① async setup() 的原理② 依赖收集流程3. 双 VNode 树与离屏渲染Off-screen / Buffer二、 简易版源码逻辑模拟三、 与 defineAsyncComponent 的协同原理四、 总结一览在 Vue 3 中Suspense是一个内置的控制流组件。它的核心使命是协调Coordinate管理其组件树深处所有异步依赖异步组件、async setup()的加载状态避免页面出现“打地鼠式”的多次闪烁实现平滑的一次性整体渲染。要理解它的底层原理可以拆解为状态机切换、异步依赖收集Promise 抛出与捕获以及双 VNode 树离屏渲染三个维度。一、 核心原理解析1. 状态机3 种状态与 2 个插槽Suspense内部维护了一个简单的状态机[ Pending (加载中) ] / \ / \ (所有异步依赖 resolve) (出现错误) \ ▼ ▼ [ Rejected ] [ Resolved (挂载完成) ]#default插槽包含真正的业务组件树可能嵌套了深层的async setup()或异步组件。#fallback插槽加载中Pending 状态时展示的骨架屏或 Loading 占位组件。2. 异步依赖收集机制巧用“Promise 抛出与捕获”Suspense是如何知道它子孙组件里有哪些东西是异步的①async setup()的原理在 Vue 3 中如果一个组件的setup()是async的或者使用了顶级await它在执行时本质上会返回一个 Promise// 编译后的 setup 函数setup(){// 当组件内部有 await 时 setup 会返回一个 PromisereturndoAsyncStuff().then((){return()h(div,Data loaded)})}② 依赖收集流程当 Vue 渲染组件树遇到一个返回 Promise 的组件或开启了suspensible的异步组件时当前组件的挂载会被暂停。该 Promise 会被向上冒泡Bubble up直到被最近的父级Suspense组件捕获Captured。Suspense内部有一个数组/计数器用来追踪所有捕获到的异步 Promise// 源码核心思路示意suspense.deps// 发现一个未完成的异步依赖计数器 1promise.then((){suspense.deps--// 完成一个计数器 -1if(suspense.deps0){suspense.resolve()// 全部完成触发状态切换}})3. 双 VNode 树与离屏渲染Off-screen / Buffer这是Suspense实现“无缝平滑切换”最关键的物理机制。如果你在已经渲染好的页面上因为某些响应式参数变化重新触发了子组件的异步加载Suspense不会立刻把当前旧页面撕掉变白离屏 DOM 树Subtree Buffer当状态变为 Pending 时Suspense会在内存中继续渲染新的#default树离屏 DOM。继续展示旧视图 / 展示 Fallback如果是首次加载直接在真实 DOM 上展示#fallback骨架屏。如果是更新加载真实 DOM 依然展示旧的#default内容新页面的渲染全在内存中进行。原子化替换Atomic Swap只有当内存中新的#default树里**所有的异步 Promise 全部resolve**之后Vue 才会执行一次 DOM 替换把内存中的 DOM 树一次性挂载到真实 DOM 上并销毁旧视图。效果用户要么看到完整的旧页面要么看到完整的新页面绝对不会看到半加载状态的残缺页面。二、 简易版源码逻辑模拟为了让你更直观地理解我们可以用一个简化版的组件来模拟Suspense的控制逻辑import{defineComponent,ref,h}fromvueexportconstMySuspensedefineComponent({name:MySuspense,setup(props,{slots}){constisResolvedref(false)constpendingDepsref(0)// 提供给子孙组件调用的注册接口实际源码中通过 internal instance 边界捕获constregisterDep(promise:Promiseany){pendingDeps.valueisResolved.valuefalsepromise.then((){pendingDeps.value--if(pendingDeps.value0){// 所有异步依赖已全部解决isResolved.valuetrue}}).catch((err){console.error(Suspense caught error:,err)})}return(){// 如果全部完成渲染 #default 插槽否则渲染 #fallback 插槽if(isResolved.value){returnslots.default?slots.default():null}else{returnslots.fallback?slots.fallback():h(div,Loading...)}}}})三、 与defineAsyncComponent的协同原理前面提到过defineAsyncComponent配置项中有suspensible: true默认值[ Async Component (defineAsyncComponent) ] │ (检查父级是否有 Suspense) │ ┌─────────┴─────────┐ ▼ ▼ [ 有 Suspense ] [ 无 Suspense ] │ │ 把加载 Promise 自己接管状态 向上抛给 Suspense 渲染自己的 loadingComponent当存在Suspense时defineAsyncComponent产生的组件在执行loader()时会把返回的 Promise 注册给上层的 Suspense 节点自己不再独立渲染loadingComponent。当不存在Suspense时它退化为独立的代理组件通过内部的ref(loaded)自行切换loadingComponent和目标组件。四、 总结一览Suspense的原理可以概括为 10 个字“捕获 Promise离屏渲染 DOM”。依赖收集利用组件setup返回 Promise 或异步组件抛出 Promise 的特性在父级拦截并统计未完成的异步任务数量。状态等待在所有 Promise 完成前维持#fallback骨架屏或保持旧视图不跳变。一次性替换通过内存离屏 DOM 树在所有依赖准备就绪后以原子操作的方式一次性挂载新组件树。 感谢阅读想了解更多 我的博客网站 | 记录思考分享干货 我的个人主页 | 关于我、开源项目

相关新闻

Unity游戏开发:使用NPOI实现Excel数据高效读写与管理

Unity游戏开发:使用NPOI实现Excel数据高效读写与管理

1. 项目概述:为什么Unity开发者需要掌握Excel数据管理?在游戏开发,尤其是Unity项目里,数据管理是个绕不开的坎。策划案里密密麻麻的数值、角色属性表、道具配置、关卡信息……这些海量数据如果全写在代码里,改一个数值…

2026/10/25 6:06:14 阅读更多 →
工艺数据溯源改造企业采购真空回流炉:封测良率提升的关键路径

工艺数据溯源改造企业采购真空回流炉:封测良率提升的关键路径

行业背景:从“经验采购”到“数据采购”的转型阵痛 在半导体封测行业,真空回流炉作为关键焊接设备,其性能直接决定了芯片封装的气密性与可靠性。过去,多数中小封测企业在采购真空回流炉时,往往依赖设备厂商提供的技术参…

2026/10/25 17:24:52 阅读更多 →
CMake工程实践:构建可复用C++项目的现代方法与最佳实践

CMake工程实践:构建可复用C++项目的现代方法与最佳实践

1. 项目概述:为什么我们需要一个“可复用”的CMake工程实践? 如果你用C做过稍微大一点的项目,或者尝试过整合几个开源库,大概率已经和CMake打过交道了。它可能是你项目根目录里那个神秘的 CMakeLists.txt 文件,也可能…

2026/10/24 1:13:40 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/10/27 17:33:32 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/10/28 7:28:00 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/10/27 7:21:53 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/10/27 18:20:50 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/10/27 6:20:47 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/10/28 7:29:02 阅读更多 →

日新闻

周新闻

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/27 13:55:19 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/27 7:21:50 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/27 19:19:37 阅读更多 →