React 任务调度、Fiber、时间切片架构关系图

35 阅读5分钟

完整架构图

┌─────────────────────────────────────────────────────────────────────┐
│                    React 调度系统完整架构图                          │
└─────────────────────────────────────────────────────────────────────┘

═══════════════════════════════════════════════════════════════════════
第 1 层:任务调度层(Update Queue)
═══════════════════════════════════════════════════════════════════════

  用户操作/事件
      ↓
  ┌──────────────────────────────────────┐
  │   创建更新(Update)                  │
  │   - setState(1) → InputLane          │
  │   - startTransition → TransitionLane │
  └──────────────────────────────────────┘
      ↓
  ┌──────────────────────────────────────┐
  │      任务队列(按优先级)             │
  ├──────────────────────────────────────┤
  │  Update A: InputLane (高)            │
  │  Update B: DefaultLane (中)          │
  │  Update C: TransitionLane (低)       │
  └──────────────────────────────────────┘
      ↓
  ┌──────────────────────────────────────┐
  │   选择最高优先级 Update               │
  │   getNextLanes(root)                 │
  └──────────────────────────────────────┘
      ↓

═══════════════════════════════════════════════════════════════════════
第 2 层:时间切片层(Scheduler)
═══════════════════════════════════════════════════════════════════════

  ┌──────────────────────────────────────┐
  │   开始执行 Update A                   │
  │   设置时间切片:5ms                   │
  │   deadline = now + 5                 │
  └──────────────────────────────────────┘
      ↓
  ┌──────────────────────────────────────┐
  │        工作循环(workLoop)          │
  │                                      │
  │  while (workInProgress) {            │
  │    ┌─ 检查 1: 有更高优先级?         │
  │    │  → Yes: 中断,重新调度          │
  │    │  → No: 继续                     │
  │    │                                 │
  │    ├─ 检查 2: 时间到了?             │
  │    │  → Yes: 让出控制权              │
  │    │  → No: 继续                     │
  │    │                                 │
  │    └─ 处理一个 Fiber 节点            │
  │  }                                   │
  └──────────────────────────────────────┘
      ↓

═══════════════════════════════════════════════════════════════════════
第 3 层:Fiber 执行层(Reconciliation)
═══════════════════════════════════════════════════════════════════════

  ┌──────────────────────────────────────────────────┐
  │         为 Update A 构建 Fiber 树                 │
  │                                                   │
  │         workInProgress 树(双缓存)               │
  │              ┌─────┐                              │
  │              │Root │                              │
  │              └──┬──┘                              │
  │        ┌────────┴────────┐                        │
  │     ┌──▼──┐          ┌──▼──┐                     │
  │     │App  │          │null │                      │
  │     └──┬──┘          └─────┘                      │
  │   ┌────┴────┐                                     │
  │ ┌─▼──┐   ┌─▼──┐                                  │
  │ │Hdr │   │Body│                                   │
  │ └────┘   └────┘                                   │
  │                                                    │
  │  链表遍历:child → sibling → return               │
  └──────────────────────────────────────────────────┘
      ↓
  ┌──────────────────────────────────────┐
  │   处理每个 Fiber 节点                 │
  │   performUnitOfWork(fiber)           │
  │   - Diff 算法                        │
  │   - 标记副作用 (flags)               │
  │   - 计算新状态                       │
  └──────────────────────────────────────┘
      ↓

═══════════════════════════════════════════════════════════════════════
第 4 层:提交层(Commit)
═══════════════════════════════════════════════════════════════════════

  ┌──────────────────────────────────────┐
  │   Fiber 树构建完成                    │
  └──────────────────────────────────────┘
      ↓
  ┌──────────────────────────────────────┐
  │   提交阶段(不可中断)                │
  │   commitRoot()                       │
  │   1. Before Mutation                 │
  │   2. Mutation (更新 DOM)             │
  │   3. 切换指针 ◄────── 双缓存         │
  │      root.current = workInProgress   │
  │   4. Layout (useEffect)              │
  └──────────────────────────────────────┘
      ↓
  ┌──────────────────────────────────────┐
  │   用户看到更新 ✅                     │
  └──────────────────────────────────────┘

时间轴视图:三者配合

时间 │ 任务调度          │ 时间切片          │ Fiber 处理
─────┼──────────────────┼──────────────────┼─────────────────
0ms  │ 选择 Update A    │ 设置 deadline    │
     │ (高优先级)       │ = 5ms            │
─────┼──────────────────┼──────────────────┼─────────────────
1ms  │                  │ 执行中...        │ 处理 Fiber 1
2ms  │                  │ 执行中...        │ 处理 Fiber 2
3ms  │                  │ 执行中...        │ 处理 Fiber 3
4ms  │                  │ 执行中...        │ 处理 Fiber 4
5ms  │                  │ 时间到!让出     │ 暂停
─────┼──────────────────┼──────────────────┼─────────────────
6ms  │                  │ 浏览器处理输入    │
─────┼──────────────────┼──────────────────┼─────────────────
7ms  │ 检查队列         │ 设置新切片       │ 继续 Fiber 5
     │ 仍是 Update A    │ deadline = 12ms  │
8ms  │                  │ 执行中...        │ 处理 Fiber 6
─────┼──────────────────┼──────────────────┼─────────────────
9ms  │ 新增 Update B!   │                  │ 处理 Fiber 7
     │ (更高优先级)     │                  │
10ms │ 检测到更高优先级 │ 中断!           │ 丢弃 workInProgress
─────┼──────────────────┼──────────────────┼─────────────────
11ms │ 切换到 Update B  │ 设置新切片       │ 开始新 Fiber 树
     │                  │ deadline = 16ms  │ 处理 Fiber 1
12ms │                  │                  │ 处理 Fiber 2
13ms │                  │                  │ 完成!提交
─────┼──────────────────┼──────────────────┼─────────────────
14ms │ 回到 Update A    │ 设置新切片       │ 重新开始 Fiber 树
     │                  │                  │ (基于新的 current)

优先级中断示意图

正在处理低优先级 Update
    │
    │  ┌─────────────────────────────────┐
    │  │ FiberA (低优先级)           │
    │  │  ✓ Fiber 1Fiber 2          │
    │  │  ✓ Fiber 3Fiber 4 (执行中) │
    │  └─────────────────────────────────┘
    │
    ↓ 高优先级 Update 插入!
    │
    ├─ 检测优先级 → 中断
    │
    ├─ 丢弃 Fiber 树 A ❌
    │
    ↓
    │  ┌─────────────────────────────────┐
    │  │ FiberB (高优先级)           │
    │  │  Fiber 1Fiber 2Fiber 3    │
    │  │  ✓ 完成 → 提交 → 显示 ✅        │
    │  └─────────────────────────────────┘
    │
    ↓ 回来处理低优先级
    │
    │  ┌─────────────────────────────────┐
    │  │ Fiber 树 A' (基于新 current)    │
    │  │  重新构建整棵树                  │
    │  │  Fiber 1 → Fiber 2 → ...        │
    │  │  ✓ 完成 → 提交 → 显示 ✅        │
    │  └─────────────────────────────────┘

层次关系图

┌─────────────────────────────────────┐
│  层次 1:Update(更新/任务)         │  ← 最高维度
│  ━━━━━━━━━━━━━━━━━━━━━━━━          │
│  - 有优先级(lane)                  │
│  - 有过期时间                        │
│  - 保存在队列中                      │
│  - 决定"做什么"                      │
└─────────────────────────────────────┘
            ↓ 执行时产生
┌─────────────────────────────────────┐
│  层次 2Fiber 树(workInProgress)  │  ← 执行产物
│  ━━━━━━━━━━━━━━━━━━━━━━━━          │
│  - 执行更新时构建的                  │
│  - 可以被丢弃                        │
│  - 完成后提交                        │
│  - 决定"如何做"                      │
└─────────────────────────────────────┘
            ↓ 由节点组成
┌─────────────────────────────────────┐
│  层次 3Fiber 节点                  │  ← 最小单元
│  ━━━━━━━━━━━━━━━━━━━━━━━━          │
│  - 树的组成单元                      │
│  - 链表连接                          │
│  - 工作的最小粒度                    │
└─────────────────────────────────────┘

映射关系:
  1 个 Update = 1 次渲染 = 1Fiber 树 = N 个 Fiber 节点

核心机制总结

任务调度(Update Scheduling)

作用:决定"做什么"
机制:优先级队列 + 过期时间
单位:Update(状态更新)
输出:选择一个 Update 执行

核心代码:
function scheduleUpdateOnFiber(fiber, lane) {
  // 标记优先级到 root
  root.pendingLanes |= lane;

  // 选择最高优先级
  const nextLane = getNextLanes(root);

  // 开始调度
  ensureRootIsScheduled(root, nextLane);
}

时间切片(Time Slicing)

作用:决定"做多久"
机制:5ms 切片 + shouldYield 检查
控制:让出浏览器控制权
输出:执行一段时间后主动暂停

核心代码:
function workLoop() {
  deadline = now + 5; // 5ms 切片

  while (workInProgress && !shouldYield()) {
    performUnitOfWork(workInProgress);
  }

  if (workInProgress) {
    port.postMessage(null); // 让出控制权
  }
}

Fiber 架构(Fiber Tree)

作用:决定"如何做"
机制:链表结构 + 可中断遍历
单位:Fiber 节点
输出:构建完整的 workInProgress 树

核心代码:
function performUnitOfWork(fiber) {
  // 处理当前节点
  reconcile(fiber);

  // 返回下一个节点(深度优先)
  if (fiber.child) return fiber.child;
  if (fiber.sibling) return fiber.sibling;
  return fiber.return;
}

完整执行流程

1. 用户触发更新
   onClick={() => setState(1)}
   ↓

2. 创建 Update 对象
   Update { lane: InputLane, payload: 1 }
   ↓

3. 加入任务队列
   root.pendingLanes |= InputLane
   ↓

4. 调度器选择最高优先级任务
   const nextLane = getNextLanes(root)
   ↓

5. 设置时间切片
   deadline = now + 5ms6. 开始构建 Fiber 树
   workInProgress = createWorkInProgress(current)
   ↓

7. 循环处理 Fiber 节点
   while (workInProgress) {
     // 检查优先级
     if (hasHigherPriority) break;

     // 检查时间
     if (shouldYield) break;

     // 处理节点
     performUnitOfWork(workInProgress);
   }
   ↓

8. 完成后提交
   commitRoot(workInProgress)
   ↓

9. 切换双缓存
   root.current = workInProgress
   ↓

10. 用户看到更新

关键检查点

检查点 1:优先级检查

function renderRoot(root, currentLane) {
  while (workInProgress) {
    const nextLanes = getNextLanes(root);

    if (nextLanes !== currentLane && nextLanes < currentLane) {
      // 有更高优先级 → 中断
      workInProgress = null;
      return;
    }

    performUnitOfWork(workInProgress);
  }
}

检查点 2:时间切片检查

function workLoop() {
  while (workInProgress && !shouldYield()) {
    performUnitOfWork(workInProgress);
  }
}

function shouldYield() {
  return performance.now() >= deadline;
}

检查点 3:过期检查

function markStarvedLanesAsExpired(root) {
  const now = performance.now();

  pendingLanes.forEach(lane => {
    if (expirationTime[lane] <= now) {
      // 过期了 → 提升为最高优先级
      root.expiredLanes |= lane;
    }
  });
}

三者协作关系

┌──────────────────────────────────────────────────┐
│              三者协作模式                         │
└──────────────────────────────────────────────────┘

任务调度 ──控制→ 时间切片 ──调度→ Fiber 执行
    ↑                               │
    └──────── 检查优先级 ←───────────┘

详细说明:

1. 任务调度 → 时间切片
   - 选择最高优先级任务
   - 设置执行时间限制

2. 时间切片 → Fiber 执行
   - 在时间限制内处理 Fiber 节点
   - 时间到了主动让出

3. Fiber 执行 → 任务调度
   - 每处理一个节点检查优先级
   - 发现更高优先级通知调度器

核心要点

三者定位:

  1. 任务调度:最高层,管理所有 Update,决定执行顺序
  2. 时间切片:中间层,控制执行时长,保证响应性
  3. Fiber:最底层,具体执行单元,可中断可恢复

协作实现:可中断的优先级渲染

  • 任务调度保证紧急的先做
  • 时间切片保证浏览器能响应
  • Fiber 架构保证可以中断和恢复

最终目标:流畅的用户体验