React Fiber 架构与渲染流程

React 的 Fiber 架构是 React 16 中引入的重大重构,它彻底改变了 React 的渲染机制,为并发特性(如 Concurrent Mode)奠定了基础。

为什么需要 Fiber 架构?

传统 Stack Reconciler 的局限性

在 React 16 之前,React 使用栈协调器(Stack Reconciler),其存在以下问题:

  1. 不可中断的递归遍历:渲染过程是同步、不可中断的
  2. 阻塞主线程:大型组件树会导致界面卡顿
  3. 无法优先处理高优先级更新:所有更新同等对待

Fiber 架构的解决方案

Fiber 架构引入了:

  1. 可中断的渲染过程:将工作分解为小单元
  2. 优先级调度:不同更新有不同的优先级
  3. 并发渲染能力:为 Concurrent Mode 提供基础

Fiber 节点的核心结构

Fiber 是 React 的最小工作单元,每个组件对应一个 Fiber 节点:

javascript 复制代码
// Fiber 节点结构(简化版)
type Fiber = {
  // 标识信息
  tag: WorkTag,           // 组件类型(函数组件、类组件、宿主组件等)
  key: null | string,     // 唯一标识
  type: any,              // 组件函数/类或DOM标签名
  
  // 树结构信息
  return: Fiber | null,   // 父节点
  child: Fiber | null,    // 第一个子节点
  sibling: Fiber | null,  // 下一个兄弟节点
  
  // 状态信息
  pendingProps: any,      // 新的 props
  memoizedProps: any,     // 上一次渲染的 props
  memoizedState: any,     // 上一次渲染的状态(hooks、state等)
  stateNode: any,         // 对应的实例(DOM节点、组件实例)
  
  // 副作用相关
  flags: Flags,           // 需要执行的副作用标记(增、删、更新)
  subtreeFlags: Flags,    // 子树中的副作用标记
  deletions: Fiber[] | null, // 待删除的子节点
  
  // 工作进度相关
  alternate: Fiber | null, // 上一次渲染的fiber节点(用于diff)
  lanes: Lanes,           // 优先级车道
  childLanes: Lanes,      // 子节点的优先级车道
  
  // Hook 相关(函数组件)
  memoizedState: any,     // Hook 链表头
};

Fiber 树的双缓存机制

React 使用双缓存技术来避免渲染过程中的视觉闪烁:

  1. Current Tree:当前屏幕上显示内容对应的 Fiber 树
  2. WorkInProgress Tree:正在构建的新 Fiber 树
javascript 复制代码
// 双缓存工作机制
function updateComponent() {
  // 从当前fiber创建workInProgress fiber
  const current = currentlyRenderingFiber.alternate;
  if (current !== null) {
    // 复用现有的fiber节点
    workInProgress = createWorkInProgress(current, pendingProps);
  } else {
    // 创建新的fiber节点
    workInProgress = createFiberFromTypeAndProps(
      // ...参数
    );
  }
  
  // 处理workInProgress树...
}

完整的渲染流程

React 的渲染过程分为两个主要阶段:

1. Render 阶段(可中断)

Render 阶段是异步、可中断的,负责计算变更:

javascript 复制代码
// Render 阶段工作循环
function workLoop(deadline) {
  let shouldYield = false;
  while (nextUnitOfWork !== null && !shouldYield) {
    // 执行当前工作单元
    nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
    
    // 检查是否需要让出主线程
    shouldYield = deadline.timeRemaining() < 1;
  }
  
  if (nextUnitOfWork !== null) {
    // 还有工作,稍后继续
    requestIdleCallback(workLoop);
  } else {
    // 所有工作完成,进入提交阶段
    commitRoot();
  }
}

performUnitOfWork 的深度优先遍历

javascript 复制代码
function performUnitOfWork(fiber) {
  // 1. 开始工作:创建子fiber节点(调用组件render方法)
  const next = beginWork(fiber);
  
  if (next !== null) {
    return next; // 如果有子节点,返回子节点继续处理
  }
  
  // 2. 没有子节点,完成当前节点工作,转向兄弟节点或父节点
  let current = fiber;
  while (current !== null) {
    // 完成当前节点(生成effect列表等)
    completeWork(current);
    
    if (current.sibling !== null) {
      return current.sibling; // 处理兄弟节点
    }
    current = current.return; // 返回父节点
  }
  
  return null; // 遍历完成
}

beginWork:处理组件更新

javascript 复制代码
function beginWork(fiber) {
  switch (fiber.tag) {
    case FunctionComponent:
      // 处理函数组件
      return updateFunctionComponent(fiber);
    case ClassComponent:
      // 处理类组件
      return updateClassComponent(fiber);
    case HostComponent:
      // 处理DOM元素
      return updateHostComponent(fiber);
    // ... 其他组件类型
  }
}

function updateFunctionComponent(fiber) {
  // 准备Hooks环境
  prepareToUseHooks(fiber);
  
  // 调用组件函数,获取子元素
  const children = fiber.type(fiber.pendingProps);
  
  // 协调子元素
  reconcileChildren(fiber, children);
  
  return fiber.child; // 返回第一个子节点
}

completeWork:完成节点处理

javascript 复制代码
function completeWork(fiber) {
  switch (fiber.tag) {
    case HostComponent:
      // 处理DOM元素的属性更新等
      if (fiber.stateNode !== null) {
        // 更新现有的DOM节点
        updateDOMProperties(fiber.stateNode, fiber.memoizedProps, fiber.pendingProps);
      } else {
        // 创建新的DOM节点
        const instance = createInstance(fiber.type, fiber.pendingProps);
        fiber.stateNode = instance;
      }
      break;
    // ... 其他组件类型
  }
  
  // 收集effect到父节点
  if (fiber.flags !== NoFlags) {
    // 将当前fiber的effect添加到父节点的effect列表中
    let parent = fiber.return;
    while (parent !== null) {
      parent.subtreeFlags |= fiber.flags;
      parent = parent.return;
    }
  }
}

2. Commit 阶段(不可中断)

Commit 阶段是同步、不可中断的,负责将变更应用到DOM:

javascript 复制代码
function commitRoot() {
  // 1. 预处理:调用getSnapshotBeforeUpdate等
  commitBeforeMutationEffects();
  
  // 2. 应用DOM变更
  commitMutationEffects();
  
  // 3. 将workInProgress树切换为current树
  root.current = finishedWork;
  
  // 4. 处理布局effect(如useLayoutEffect)
  commitLayoutEffects();
  
  // 5. 调度被动effect(useEffect)
  schedulePassiveEffects();
}

commitMutationEffects:处理DOM变更

javascript 复制代码
function commitMutationEffects() {
  // 遍历effect列表,执行DOM操作
  while (nextEffect !== null) {
    const flags = nextEffect.flags;
    
    if (flags & Placement) {
      // 插入新节点
      commitPlacement(nextEffect);
    }
    if (flags & Update) {
      // 更新节点
      commitUpdate(nextEffect);
    }
    if (flags & Deletion) {
      // 删除节点
      commitDeletion(nextEffect);
    }
    
    nextEffect = nextEffect.nextEffect;
  }
}

优先级调度机制

Fiber 架构引入了优先级概念,确保高优先级更新优先处理:

javascript 复制代码
// 优先级类型(简化)
const SyncLane = 0b0000000000000000000000000000001; // 同步优先级
const InputContinuousLane = 0b0000000000000000000000000000100; // 连续输入
const DefaultLane = 0b0000000000000000000000000010000; // 默认优先级

// 基于优先级的调度
function scheduleUpdateOnFiber(fiber, lane) {
  // 标记优先级
  fiber.lanes = mergeLanes(fiber.lanes, lane);
  
  // 调度更新
  if (lane === SyncLane) {
    // 同步更新,立即执行
    performSyncWorkOnRoot(root);
  } else {
    // 异步更新,根据优先级调度
    ensureRootIsScheduled(root);
  }
}

并发模式下的工作方式

在并发模式下,React 可以中断低优先级工作来处理高优先级更新:

javascript 复制代码
// 高优先级更新中断低优先级工作
function handleUserInput() {
  // 高优先级更新(用户输入)
  scheduleUpdateOnFiber(root, InputContinuousLane);
  
  // 如果当前有低优先级渲染正在进行...
  // React 会中断它,先处理高优先级更新
}

// 被中断的工作可以稍后重新开始
function resumeInterruptedWork(interruptedFiber) {
  // 从中断的地方继续工作
  nextUnitOfWork = interruptedFiber;
  requestIdleCallback(workLoop);
}

错误处理机制

Fiber 架构改进了错误处理:

javascript 复制代码
function renderRoot() {
  try {
    // 正常的渲染工作
    workLoop();
  } catch (error) {
    // 处理错误,寻找错误边界
    let fiber = nextUnitOfWork;
    while (fiber !== null) {
      if (fiber.tag === ClassComponent && 
          typeof fiber.type.getDerivedStateFromError === 'function') {
        // 找到错误边界组件
        captureError(fiber, error);
        break;
      }
      fiber = fiber.return;
    }
    
    // 重新尝试渲染
    restartRender();
  }
}

性能优化特性

1. 增量渲染

Fiber 将渲染工作分解为小单元,可以分段完成:

javascript 复制代码
// 时间分片示例
function workLoopConcurrent(deadline) {
  while (nextUnitOfWork !== null && deadline.timeRemaining() > 0) {
    nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
  }
  
  if (nextUnitOfWork !== null) {
    // 还有工作,稍后继续
    requestIdleCallback(workLoopConcurrent);
  }
}

2. 子树渲染跳过

当 props 未变化时,可以跳过整个子树的渲染:

javascript 复制代码
function bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes) {
  if (current !== null) {
    // 检查props是否变化
    const oldProps = current.memoizedProps;
    const newProps = workInProgress.pendingProps;
    
    if (oldProps === newProps && !hasContextChanged()) {
      // props未变化,可以跳过整个子树
      return null;
    }
  }
  
  // 需要重新渲染
  return updateFunctionComponent(workInProgress);
}

总结

React Fiber 架构的核心创新:

  1. 可中断的异步渲染:将渲染工作分解为小单元,可以暂停和恢复
  2. 优先级调度:不同更新有不同优先级,确保用户体验流畅
  3. 双缓存机制:避免渲染过程中的视觉闪烁
  4. 增量提交:DOM 变更分批进行,减少布局抖动
  5. 更好的错误处理:完善的错误边界机制

参考: incepter.github.io/how-react-w...

相关推荐
崔庆才丨静觅2 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60613 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了3 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅3 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅4 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅4 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment4 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅4 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊4 小时前
jwt介绍
前端
爱敲代码的小鱼5 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax