React 可中断恢复

社区来稿 · Liu由用户发布,不代表 batype 本人观点

·469 字 · 约 1 分钟

例子+图解+流程说明,帮你理解高优先级任务如何中断、恢复,以及 workInProgress 树的构建过程。

场景举例#

假设有如下组件树:

<App>
  <A />
  <B />
  <C />
</App>
  • 用户在 A 组件中输入内容(低优先级,startTransition 包裹)。

  • 渲染到 B 组件时,用户突然点击了 C 组件的按钮(高优先级)。

1. 初始渲染(低优先级)#

  • React 开始构建 workInProgress 树,从 -> -> -> 。

  • 由于是低优先级(比如 startTransition),React 每处理一部分 Fiber 节点就会“让出”控制权,检查是否有更高优先级任务。

2. 中断发生#

  • 当 React 渲染到 时,用户在 上触发了高优先级事件(比如点击)。

  • React 检查到有高优先级任务到来,中断当前的 workInProgress 构建,把控制权交还给浏览器,优先处理高优先级事件。

3. 高优先级任务插队#

  • React 以高优先级开始处理 的点击事件,可能会触发 组件的 setState。

  • 这时,React 会判断:

    • 如果 的更新和之前的 workInProgress 树没有冲突,可以在原有 workInProgress 树基础上继续构建(恢复)。

    • 如果有冲突(比如 的更新影响了 或 ),则丢弃当前 workInProgress 树,重新从 current 树生成新的 workInProgress 树。

4. 恢复渲染#

  • 假设 的更新只影响自己,React 会把高优先级的更新插入到 workInProgress 树的 节点。

  • React 继续遍历 workInProgress 树,从中断点( 后)恢复,完成剩余节点的构建。

5. 图解(Mermaid)#

graph TD
  A1["<App> (current)"]
  A2["<A> (current)"]
  A3["<B> (current)"]
  A4["<C> (current)"]

  B1["<App> (workInProgress)"]
  B2["<A> (workInProgress)"]
  B3["<B> (workInProgress)"]
  B4["<C> (workInProgress)"]

  A1 --> A2 --> A3 --> A4
  B1 --> B2 --> B3 --> B4

  subgraph 渲染阶段
    B1
    B2
    B3
    B4
  end

  click B3 "中断点"
  click B4 "高优先级插队"

6. 伪代码流程#

// 1. 低优先级渲染
workInProgress = createWorkInProgress(current, lowPriorityUpdate);
beginWork(workInProgress); // 渲染<App>、<A>、<B>

// 2. 检查到高优先级任务
if (hasHighPriorityTask) {
  // 3. 判断是否可以复用workInProgress
  if (canReuseWorkInProgress(workInProgress, highPriorityUpdate)) {
    // 4. 合并高优先级更新,恢复渲染
    mergeUpdate(workInProgress, highPriorityUpdate);
    resumeWork(workInProgress, from: interruptedPoint);
  } else {
    // 5. 丢弃,重建workInProgress
    workInProgress = createWorkInProgress(current, highPriorityUpdate);
    beginWork(workInProgress);
  }
}

7. 总结#

  • React 渲染 workInProgress 树时,遇到高优先级任务会中断。

  • 如果新旧任务能合并,workInProgress 树会被复用,恢复渲染。

  • 如果不能合并,则丢弃当前 workInProgress,重新构建。

  • 这种机制让 React 能灵活响应用户操作,提升体验。