认识
2023年12月28日
一、认识
React.lazy
内部模拟一个 promiseA
规范场景。完全可以理解 React.lazy
用 Promise
模拟了一个请求数据的过程,但是请求的结果不是数据,而是一个动态的组件。下一次渲染就直接渲染这个组件,所以是 React.lazy
利用 Suspense
接收 Promise
,执行 Promise
,然后再渲染这个特性做到动态加载的,代码如下:
react/src/ReactLazy.js
function lazy(ctor){
return {
$$typeof: REACT_LAZY_TYPE,
_payload:{
_status: -1, //初始化状态
_result: ctor,
},
_init:function(payload){
if(payload._status===-1){ /* 第一次执行会走这里 */
const ctor = payload._result;
const thenable = ctor();
payload._status = Pending;
payload._result = thenable;
thenable.then((moduleObject)=>{
const defaultExport = moduleObject.default;
resolved._status = Resolved; // 1 成功状态
resolved._result = defaultExport;/* defaultExport 为我们动态加载的组件本身 */
})
}
if(payload._status === Resolved){ // 成功状态
return payload._result;
}
else { //第一次会抛出Promise异常给Suspense
throw payload._result;
}
}
}
}
整个流程是这样的,React.lazy
包裹的组件会标记 REACT_LAZY_TYPE
类型的 element
,在调和阶段会变成 LazyComponent
类型的 fiber
,React
对 LazyComponent
会有单独的处理逻辑:
-
第一次渲染首先会执行
init
方法,里面会执行lazy
的第一个函数,得到一个Promise
,绑定Promise.then
成功回调,回调里得到将要渲染组件defaultExport
,这里要注意的是,如上面的函数当第二个if
判断的时候,因为此时状态不是Resolved
,所以会走else
,抛出异常Promise
,抛出异常会让当前渲染终止。 -
这个异常
Promise
会被Suspense
捕获到,Suspense
会处理Promise
,Promise
执行成功回调得到defaultExport
(将想要渲染组件),然后Susponse
发起第二次渲染,第二次init
方法已经是Resolved
成功状态,那么直接返回result
也就是真正渲染的组件。这时候就可以正常渲染组件了