ReactFiber在并发模式下的运行机制
新一年又开始了,React过去一年悄悄实现了Suspense,带来了React Hooks ,源码也大变换了。因此好有必须重新阅读一下,看它是如何实现这些功能,及未来准备开放的并发渲染功能。
React16早期将原来的diff过程拆分成两个阶段,第一个阶段叫 reconcile , 也就是原来diff虚拟DOM的过程。这阶段有大量叫reconcileXXX的方法参与其中,如reconcileSingleElement、reconcileSinglePortal、reconcileChildFibers、reconcileSingleTextNode、 reconcileChildrenArray、reconcileChildrenIterator、 reconcileChildFibers...会创建组件实例与真实DOM节点,执行一些轻量钩子。第二个阶段叫commit,在并发模式下,可能多次reconcile才有一次commit。commit就是将水面下的效果浮现出来,比如将节点插入到DOM树,修复节点的属性样式文本内容,执行如componentDidXXX这样的重量钩子,执行ref操作(这时可能涉及DOM操作)。
schedule源码剖析
现在,React在这两个阶段之前新添加了一个阶段,schedule。因为一个页面可能有多个ReactDOM.render,虚拟DOM树中也通常存在多个拥有自更新能力的组件(React Hooks的出现让无状态组件也具有自更新能力)。在并发模式下,组件setState不会立即更新视图,于是在一个时间段中,就有多个待更新的组件,这些组件叫root(渲染的起点),但谁是真正的nextRoot呢?需要一个调度算法进行决定。React根据当前时间给每个组件分配一个过期时间(相当优先级),数字越大,就越优先执行。
schedule的起点方法是scheduleWork。 ReactDOM.render, setState,forceUpdate, React Hooks的dispatchAction都要经过scheduleWork。
scheduleWork里面有一个scheduleWorkToRoot方法,负责将当前fiber及其alternate的过期时间推迟(或者叫加大)。由于在ReactFiber中,过期时间等价于优先级,换言之,一个组件在某个时间段setState频繁,那么它就越优先更新。
在并发模式下,setState后33ms执行(如果在动画中,为了保证流畅,增长到100ms间隔 )。如果更新的节点是一个受控组件(input),那么它是直接进入interactiveUpdates方法,不经过scheduleWork,是立即更新!React还有一个没登记到文档batchedUpdates方法,它可以让一大遍节点立即更新,并且无视shouldComponentUpdate return false!!类似batchedUpdates这样的特权方法,在React16中已经存在了许多了!
上面是ReactFiber的总流程。最下面的绿色方法都是贵族方法,拥有极高的优先执行权。
//by 司徒正美 QQ 370262116
function scheduleWork(fiber, expirationTime) {
const root = scheduleWorkToRoot(fiber, expirationTime);
if (root === null) {
return;
}
if (
!isWorking &&
nextRenderExpirationTime !== NoWork &&
expirationTime > nextRenderExpirationTime
) {
resetStack();
}
markPendingPriorityLevel(root, expirationTime);
if (
//如果在准备阶段或commitRoot阶段或渲染另一个节点
!isWorking ||
isCommitting ||
// ...unless this is a different root than the one we're rendering.
nextRoot !== root
) {
const rootExpirationTime = root.expirationTime;
requestWork(root, rootExpirationTime);
}
}
requestWork是决定以什么方式进入performWorkOnRoot。有四种情况,一如果已经开始渲染,那么就立即返回,二是直接进入performWorkOnRoot, 三是先进入performSyncWork,然后到performSync到performWork到performWorkOnRoot,四是异步方