在面试过程中提到懒加载,很多的面试官都喜欢再往深一点问:也就是懒加载的原理。
笔者也是在两次面试过程中被问过,所以写了这一篇文章。
🤖 举一个最简单的例子
一个懒加载组件,promise加载完成之前显示loading,加载完成之后就显示实际的组件Lazy
懒加载就这么简单,所以面试的时候问到这个问题,一般都想考一下你是否明白他的原理,一般不懂也没关系,如果你懂一点,就可以和其他面试者区分开来了。
当然现在这行情懂不懂也无所谓了。😭
const Lazy = React.lazy(
() =>
new Promise((resolve) => {
setTimeout(() => {
resolve({ default: () => <div>Lazy</div> })
}, 2000)
}),
)
function App() {
return (
<Suspense fallback='loading'>
<Lazy />
</Suspense>
)
}
🤖 小科普:科普一下react原理,不用担心,小白也能看懂
render阶段创建fiber树
commit阶段遍历fiber树创建一棵dom树出来
🤖 原理解析
React.lazy和Suspense的源码就不放了,之前写的源码解析文章推荐到首页也没多少人看😭所以直接讲原理
初步原理
promise 没有加载完成前,Suspense Fiber 下面创建的是 fallback Fiber,也就是这个 loading
组件加载完成,suspense fiber 的子节点去挂载真正的组件,也就是这个 Lazy 组件
更细节的原理
可以看到在render阶段,react 会执行一个循环,不断的执行beginWork,一个一个的创建 fiber 节点
如上图
beginWork创建App Fiber,然后Suspense Fiber,然后Lazy Fiber,然后div Fiber
do {
try {
while (workInProgress) {
const next = beginWork(workInProgress)
workInProgress = next
}
break
} catch (thrownValue) {
handleError(root, thrownValue)
}
} while (true)
-
beginWork创建到Lazy Fiber的时候,只要组件未加载完成,也就是这个React.lazy这个promise还在pending,promise就会被当做错误throw抛出 -
错误被上面的
handleError捕获到,他会- 找到最近的父亲
Suspense Fiber - 给
Suspense Fiber标记DidCapture Flag - 把 React.lazy 的
promise保存在suspense Fiber的updateQueue - 把
workInProgress又指向Suspense Fiber
- 找到最近的父亲
-
处理完错误,这时候又开始
beginWork工作循环。经过刚才的错误,workInProgress从Lazy Fiber变成了他的父亲Suspense Fiber也就是说我们的
beginWork现在是第二次处理Suspense,这时候发现刚才标记的DidCapture Flag,他就会先创建一个fallback Fiber
那等一下这个
fallback Fiber创建的dom是不是就是我们下图中的loading啊,介就算齐活了,页面就显示了一个loading的骨架屏了。
页面 loading 是出来了,那实际的 lazy 组件怎么渲染出来呢?
-
我们上面说处理错误的时候,
Suspense Fiber是不是有一个updateQueue,保存了React.lazy的promise。 -
那其实在
commit阶段我们遍历fiber树创建Dom树的时候,遍历到Suspense Fiber,他会给updateQueue里面的promise注册一个回调promise.then(回调) -
当
promise resolved了,也就是远程组件懒加载好了,触发回调,回调里面就是会重新开始工作循环创建新fiber树,并且给Suspense组件做标记,告诉react等一下suspense组件要重渲染。 -
工作循环走到
suspense的beginWork进行重渲染,这次没有标记DidCapture Flag,所以这次就创建Lazy Fiber而不是fallback Fiber
这里面我简化了一部分,去掉了里面关于
OffScreen这个react的内置组件,也就是常说的react版的KeepAlive
🤖 总结
这么回答,应该能拿到六七十分,那么这个问题你在面试官那里就算过了 😊
但是其实这个问题只有一面同事面会问,二面项目面才是重点😭
🤖 相关
面试官:让你实现一个高性能 Tree 组件磕磕绊绊的,你好意思干了三年前端?我:😭
面试官:听说你简历里写的精通 React 源码,那你给我讲讲 React Scheduler 呗?我:😡 工资加 2K
面试官:你说你做过组件库,肯定了解过复杂组件状态管理的useSyncExternalStore吧?我:😭
版权归许泽川所有
如需转载,请提前询问本人的许可