在面试过程中提到懒加载,很多的面试官都喜欢再往深一点问:也就是懒加载的原理。
笔者也是在两次面试过程中被问过,所以写了这一篇文章。
🤖 举一个最简单的例子
一个懒加载组件,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吧?我:😭
版权归许泽川所有
如需转载,请提前询问本人的许可