suspense 和 lazy 配合实现懒加载的原理浅析

先看下面这段代码

javascript 复制代码
// lazy.js
function Fn() {
  return <div className="App">
    函数组件
  </div>
}

// app.js
// 添加一个固定的延迟时间,以便你可以看到加载状态
function delayForDemo(promise) {
  return new Promise(resolve => {
    setTimeout(resolve, 5000);
  }).then(() => promise);
}

const LazyFn = lazy(() => delayForDemo(import('./lazy.js')));
function SuspendedApp() {
  return (
    <Suspense fallback={<div>加载中。。。</div>}>
      <LazyFn />
    </Suspense>
  )
}


const root = ReactDOM.createRoot(document.getElementById('app'));

root.render(
  <SuspendedApp />
);

这段代码模拟了懒加载的过程,运行之后,屏幕上会先展示 Suspense 的 fallback ------ 加载中。。。 过 5 秒钟加载到组件后会自动重新渲染屏幕上出现 函数组件。。。。那这个 React 是怎么实现的呢,下面我们来看看实现的流程。

实现流程

这个流程发生在 Render 阶段。

  1. 从根节点开始挨个执行 beginWork 方法(不太清楚的话可以看看Render流程
  2. 执行到 Suspense 的 beginWork 时,会通过 Didcaptrue 来判断是否展示 fallback 内容,第一次执行默认不展示 fallback,走正常渲染子节点
  3. 正常渲染 lazy 节点,结果返回一个 Promise,Promise 肯定没办法渲染啊,所以把这个Promise作为异常抛出
  4. 异常被捕获,发现异常是一个 Promise,为这个 Promise.then 传入了一个触发更新的方法,并找到距离这个 lazy 组件最近的 Suspense 组件并标记 shouldCapture 为 true,后续处理后标记 DidCaptrue 为 true
  5. 重新执行 Suspense 的 beginWork 方法,此时第二次执行,Didcaptrue 为 true ,展示 fallback 内容,同时把 Didcaptrue 置为 false。
  6. 懒加载的组件加载完成,触发更新,和步骤 1 一样
  7. 执行 Suspense 的 beginWork 方法,DidCaptrue 为 false,正常展示子节点
  8. 渲染 lazy 节点,此时拿到了组件,正常渲染组件

以上就是主要的实现流程(当然实际会比上面介绍的复杂一点)。

源码环节

先是 Suspense 执行 beginWork

这里就是通过 Didcaptrue 来判断 showFallback 的值的。 第一次执行 showFallback 为 false ,因此先正常展示子节点

之后会处理 OffscreenComponent, 完了才会处理 lazy 组件,这个方法里最关键的就是 init 方法 也是在 init 方法里面抛出了异常

接下来是捕获异常,先是被beginWork 捕获,再抛出,最终被 renderRootSync 函数的错误处理捕获处理

接下来重新处理 Suspense,此时showFallback 为 true,同时处理了子节点和 Fallback 节点,最终返回Fallback节点,并渲染

接下来Promise被解决

再次处理 Suspense,更新子节点

然后处理 OffscreenComponent,再处理 lazy 节点

然后就是正常的渲染流程了,流程结束 懒加载的组件 替换 fallback 展示到页面上

最后

以上就是我梳理的 suspense 和 lazy 组合的工作流程,感谢大家的阅读,有不对的地方也欢迎大家指出来。

参考

  • React 18.2.0 源码
相关推荐
葡萄城技术团队4 分钟前
从自然语言到表格操作:SpreadJS 表格智能体如何执行一个任务
前端
Neighbor_OldY44 分钟前
【实战复盘】文件上传漏洞检测与应急处置:校验绕过、图片马与WebShell的排查修复指南
运维·前端·web安全
金花顺44 分钟前
android_media_AudioTrack_setup
前端
晓天衡宇•评测社区1 小时前
Seedance 2.5 登顶图生视频榜单,Wan 3.0 在游戏与教育场景进入前列
前端·javascript·网络
码海无涯回头无岸1 小时前
Ai agent - LLM是一个函数
前端
Profile排查笔记1 小时前
指纹浏览器推荐:用一套验收清单筛选 Profile、代理与自动化能力
前端·人工智能·后端·自动化
卡皮巴拉c991 小时前
基于pnpm搭建monorepo项目
前端·javascript
jianpeng的工程笔记1 小时前
Colab Kaggle 防断开脚本
javascript·深度学习·kaggle·colab
yume_sibai1 小时前
CSS2 核心知识点完全总结(选择器 + 三大特性 + 常用属性)
前端·css
掘金者阿豪1 小时前
不装 SSH 客户端也能连服务器:用 WebSSH 把终端搬进浏览器
前端