ReactDOM.render 串联渲染链路 —— render 阶段“递归”概览

参考文章:React技术揭秘——render阶段

简要回顾

render阶段开始于performSyncWorkOnRootperformConcurrentWorkOnRoot方法的调用。这取决于本次更新是同步更新还是异步更新。

未使用 Concurrent,同步更新

使用 Concurrent模式,进行异步更新

这两个方法的主要区别如下:

// performSyncWorkOnRoot会调用该方法
function workLoopSync() {
  while (workInProgress !== null) {
    performUnitOfWork(workInProgress);
  }
}

// performConcurrentWorkOnRoot会调用该方法
function workLoopConcurrent() {
  while (workInProgress !== null && !shouldYield()) {
    performUnitOfWork(workInProgress);
  }
}

可以看到,他们唯一的区别是是否调用shouldYield。如果当前浏览器帧没有剩余时间,shouldYield会中止循环,直到浏览器有空闲时间后再继续遍历。这就是开启Concurrent模式后,原本的同步更新,通过时间切片(每帧时,留出一点固定时间给JS)变为可中断的异步更新。

我们要记住,Fiber Reconciler 是从 Stack Reconciler 重构而来。所以本质上在渲染时,还是要"递归",只不过这个"递归"现在是通过遍历的方式实现可中断的"递归"。

同时performSyncWorkOnRootperformConcurrentWorkOnRoot的源码区别中也有一个很关键的对象:workInProgress,详情可以点击这里查看

“递归”流程概览

  • “递”(为每个遍历到的 Fiber 节点调用 beginWork 方法):从rootFiber开始向下深度优先遍历。为遍历到的每个Fiber节点,当遍历到叶子节点(即没有子组件的组件)时就会进入“归”阶段。
  • “归”(调用completeWork 处理 Fiber节点)
    • 当某个Fiber节点执行完completeWork,如果其存在兄弟Fiber节点(即fiber.sibling !== null),会进入其兄弟Fiber的“递”阶段。
    • 如果不存在兄弟Fiber,会进入父级Fiber的“归”阶段。

“递”和“归”阶段会交错执行直到“归”到rootFiber。至此,render阶段的工作就结束了。

举例说明
function App() {
  return (
    
i am KaSong
) } ReactDOM.render(, document.getElementById("root"));

对应的 Fiber树结构


child属性 表示子节点,return 属性表示父节点,sibling 属性表示兄弟节点

render 阶段依次执行:

1. rootFiber beginWork    //递
2. App Fiber beginWork    //递
3. div Fiber beginWork    //递
4. "i am" Fiber beginWork  //递
5. "i am" Fiber completeWork    //没有兄弟节点,归
6. span Fiber beginWork    //有兄弟节点,递
7. span Fiber completeWork    //没有兄弟节点,归
8. div Fiber completeWork    //没有兄弟节点,归
9. App Fiber completeWork    //没有兄弟节点,归
10. rootFiber completeWork    //没有兄弟节点,归

注意:之所以没有 “KaSong” Fiber 的 beginWork/completeWork,是因为作为一种性能优化手段,针对只有单一文本子节点的Fiber,React会特殊处理。

由于 beginWork / completeWork 内容太多,我再另外记录。

你可能感兴趣的:(ReactDOM.render 串联渲染链路 —— render 阶段“递归”概览)