八、唠嗑一下 React Fiber工作原理

React Fiber 是 React 16 引入的核心算法重构,通过 增量渲染优先级调度 机制优化性能,其工作原理可概括为以下关键点:

一、核心目标

  1. 解决阻塞问题:将同步递归渲染改为异步可中断任务,避免长时间占用主线程导致页面卡顿。
  2. 优先级调度:区分高/低优先级任务(如用户交互 vs 数据加载),确保高优先级任务优先执行。
  3. 增量渲染:将渲染任务拆分为多个小单元(时间片),在浏览器空闲时逐步完成。 下面是一段JSX 代码到 DOM 节点的转换过程:

二、核心机制

1. Fiber 数据结构

js 复制代码
// A Fiber is work on a Component that needs to be done or was done. There can
// be more than one per component.
export type Fiber = {
  // These first fields are conceptually members of an Instance. This used to
  // be split into a separate type and intersected with the other Fiber fields,
  // but until Flow fixes its intersection bugs, we've merged them into a
  // single type.

  // An Instance is shared between all versions of a component. We can easily
  // break this out into a separate object to avoid copying so much to the
  // alternate versions of the tree. We put this on a single object for now to
  // minimize the number of objects created during the initial render.

  // Tag identifying the type of fiber.
  tag: WorkTag,

  // Unique identifier of this child.
  key: null | string,

  // The value of element.type which is used to preserve the identity during
  // reconciliation of this child.
  elementType: any,

  // The resolved function/class/ associated with this fiber.
  type: any,

  // The local state associated with this fiber.
  stateNode: any,

  // Conceptual aliases
  // parent : Instance -> return The parent happens to be the same as the
  // return fiber since we've merged the fiber and instance.

  // Remaining fields belong to Fiber

  // The Fiber to return to after finishing processing this one.
  // This is effectively the parent, but there can be multiple parents (two)
  // so this is only the parent of the thing we're currently processing.
  // It is conceptually the same as the return address of a stack frame.
  return: Fiber | null,

  // Singly Linked List Tree Structure.
  child: Fiber | null,
  sibling: Fiber | null,
  index: number,

  // The ref last used to attach this node.
  // I'll avoid adding an owner field for prod and model that as functions.
  ref:
    | null
    | (((handle: mixed) => void) & {_stringRef: ?string, ...})
    | RefObject,

  refCleanup: null | (() => void),

  // Input is the data coming into process this fiber. Arguments. Props.
  pendingProps: any, // This type will be more specific once we overload the tag.
  memoizedProps: any, // The props used to create the output.

  // A queue of state updates and callbacks.
  updateQueue: mixed,

  // The state used to create the output
  memoizedState: any,

  // Dependencies (contexts, events) for this fiber, if it has any
  dependencies: Dependencies | null,

  // Bitfield that describes properties about the fiber and its subtree. E.g.
  // the ConcurrentMode flag indicates whether the subtree should be async-by-
  // default. When a fiber is created, it inherits the mode of its
  // parent. Additional flags can be set at creation time, but after that the
  // value should remain unchanged throughout the fiber's lifetime, particularly
  // before its child fibers are created.
  mode: TypeOfMode,

  // Effect
  flags: Flags,
  subtreeFlags: Flags,
  deletions: Array<Fiber> | null,

  lanes: Lanes,
  childLanes: Lanes,

  // This is a pooled version of a Fiber. Every fiber that gets updated will
  // eventually have a pair. There are cases when we can clean up pairs to save
  // memory if we need to.
  alternate: Fiber | null,

  // Time spent rendering this Fiber and its descendants for the current update.
  // This tells us how well the tree makes use of sCU for memoization.
  // It is reset to 0 each time we render and only updated when we don't bailout.
  // This field is only set when the enableProfilerTimer flag is enabled.
  actualDuration?: number,

  // If the Fiber is currently active in the "render" phase,
  // This marks the time at which the work began.
  // This field is only set when the enableProfilerTimer flag is enabled.
  actualStartTime?: number,

  // Duration of the most recent render time for this Fiber.
  // This value is not updated when we bailout for memoization purposes.
  // This field is only set when the enableProfilerTimer flag is enabled.
  selfBaseDuration?: number,

  // Sum of base times for all descendants of this Fiber.
  // This value bubbles up during the "complete" phase.
  // This field is only set when the enableProfilerTimer flag is enabled.
  treeBaseDuration?: number,

  // Conceptual aliases
  // workInProgress : Fiber ->  alternate The alternate used for reuse happens
  // to be the same as work in progress.
  // __DEV__ only

  _debugInfo?: ReactDebugInfo | null,
  _debugOwner?: ReactComponentInfo | Fiber | null,
  _debugStack?: string | Error | null,
  _debugTask?: ConsoleTask | null,
  _debugNeedsRemount?: boolean,

  // Used to verify that the order of hooks does not change between renders.
  _debugHookTypes?: Array<HookType> | null,
};

Fiber 可以理解成一个工作单元,每次执行完一个工作单元,react 就会检查还剩余多少时间,如果没有就把控制权交还给浏览器。

2. 任务调度调度(Reconciliation)

任务拆分:将渲染任务分解为多个小单元(Work Unit),每个单元处理一个 Fiber 节点。

优先级判断:根据任务类型分配优先级,高优先级任务可中断低优先级任务。

时间切片 :通过 requestIdleCallback 控制单帧执行时间,避免阻塞主线程。

React Fiber 与浏览器的核心交互过程如下:

首先 React 向浏览器请求调度,浏览器在一帧中如果还有空闲时间,会去判断是否存在待执行任务,不存在就直接将控制权交给浏览器,如果存在就会执行对应的任务,执行完成后会判断是否还有时间,有时间且有待执行任务则会继续执行下一个任务,否则就会将控制权交给浏览器。

3. 双缓存 Fiber 树

React 中存在两棵树,一颗为current Fiber tree,另外一颗为workInProgress Fiber tree。

在全局变量中有workInProgress, 还有不少以workInProgress来命名的变量. workInProgress的应用实际上就是React的双缓冲技术(double buffering). fiber树的构造过程, 就是把ReactElement转换成fiber树的过程. 在这个过程中, 内存里会同时存在 2 棵fiber树:

  • 其一: 代表当前界面的fiber树(已经被展示出来, 挂载到fiberRoot.current上). 如果是初次构造(初始化渲染), 页面还没有渲染, 此时界面对应的 fiber 树为空(fiberRoot.current = null).
  • 其二: 正在构造的fiber树(即将展示出来, 挂载到HostRootFiber.alternate上, 正在构造的节点称为workInProgress). 当构造完成之后, 重新渲染页面, 最后切换fiberRoot.current = workInProgress, 使得fiberRoot.current重新指向代表当前界面的fiber树.

此处涉及到 2 个全局对象fiberRootHostRootFiber,

用图来表述double buffering的概念如下:

  1. 构造过程中, fiberRoot.current指向当前界面对应的fiber树.
  1. 构造完成并渲染, 切换fiberRoot.current指针, 使其继续指向当前界面对应的fiber树(原来代表界面的 fiber 树, 变成了内存中).

三、与传统 React 的对比

特性 React 15(Stack Reconciler) React 16+(Fiber Reconciler)
渲染方式 同步递归,不可中断 异步迭代,可中断/恢复
优先级支持 支持动态优先级调度
性能表现 复杂树渲染易卡顿 分片渲染,保持 UI 响应
适用场景 简单应用 大型/复杂应用

四、总结

React Fiber 通过 增量渲染优先级调度 实现高效的任务管理,其核心优势在于:

响应性提升:避免长时间阻塞主线程,保障交互流畅。

性能优化:仅更新实际变化的部分,减少计算开销。

扩展性增强:支持并发模式(Concurrent Mode)和错误边界等高级特性。

通过这种设计,React Fiber 成为现代 Web 应用高性能渲染的基石。

相关推荐
烛阴1 分钟前
JavaScript Rest 参数:新手也能轻松掌握的进阶技巧!
前端·javascript
chenchihwen4 分钟前
ITSM统计分析:提升IT服务管理效能 实施步骤与操作说明
java·前端·数据库
陌上烟雨寒8 分钟前
es6 尚硅谷 学习
前端·学习·es6
拉不动的猪9 分钟前
刷刷题32(uniapp初级实际项目问题-1)
前端·javascript·面试
拉不动的猪10 分钟前
刷刷题33(uniapp初级实际项目问题-2)
前端·javascript·面试
han_21 分钟前
JavaScript如何实现复制图片功能?
前端·javascript
崽崽的谷雨43 分钟前
react实现一个列表的拖拽排序(react实现拖拽)
前端·react.js·前端框架
小小坤1 小时前
前端基于AI生成H5 vue3 UI组件
前端·javascript·vue.js
既见君子2 小时前
透明视频
前端