React Render 阶段

156 阅读2分钟

render 阶段主要做什么

在 render 阶段,React 可以根据当前可用的时间片处理一个或多个 fiber 节点,并且得益于 fiber 对象中存储的元素上下文信息以及指针域构成的链表结构,使其能够将执行到一半的工作保存在内存的链表中。当 React 停止并完成保存的工作后,让出时间片去处理一些其他优先级更高的事情。之后,在重新获取到可用的时间片后,它能够根据之前保存在内存的上下文信息通过快速遍历的方式找到停止的 fiber 节点并继续工作。由于在此阶段执行的工作并不会导致任何用户可见的更改,因为并没有被提交到真实的 DOM。所以,我们说是 fiber 让调度能够实现暂停、中止以及重新开始等增量渲染的能力;

render阶段开始于performSyncWorkOnRootperformConcurrentWorkOnRoot方法的调用。 这取决于本次更新是同步更新还是异步更新。 这两个方法分别会调用下面两个方法—— workLoopSync 和 workLoopConcurrent:

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

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

可以看到,他们唯一的区别是是否调用 shouldYield。如果当前浏览器帧没有剩余时间,shouldYield 会中止循环,直到浏览器有空闲时间后再继续遍历

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

“递归”流程概览

  • “递”(为每个遍历到的 Fiber 节点调用 beginWork 方法) :从rootFiber开始向下深度优先遍历。为遍历到的每个Fiber节点,当遍历到叶子节点(即没有子组件的组件)时就会进入“归”阶段。

  • “归”(调用completeWork 处理 Fiber节点)

    • 当某个Fiber节点执行完completeWork,如果其存在兄弟Fiber节点(即fiber.sibling !== null),会进入其兄弟Fiber的“递”阶段。
    • 如果不存在兄弟Fiber,会进入父级Fiber的“归”阶段。

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