React Fiber 是 React 16 引入的核心算法重构,通过 增量渲染 和 优先级调度 机制优化性能,其工作原理可概括为以下关键点:
一、核心目标
- 解决阻塞问题:将同步递归渲染改为异步可中断任务,避免长时间占用主线程导致页面卡顿。
- 优先级调度:区分高/低优先级任务(如用户交互 vs 数据加载),确保高优先级任务优先执行。
- 增量渲染:将渲染任务拆分为多个小单元(时间片),在浏览器空闲时逐步完成。 下面是一段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 个全局对象fiberRoot
和HostRootFiber
,
用图来表述double buffering
的概念如下:
- 构造过程中,
fiberRoot.current
指向当前界面对应的fiber
树.
- 构造完成并渲染, 切换
fiberRoot.current
指针, 使其继续指向当前界面对应的fiber
树(原来代表界面的 fiber 树, 变成了内存中).
三、与传统 React 的对比
特性 | React 15(Stack Reconciler) | React 16+(Fiber Reconciler) |
---|---|---|
渲染方式 | 同步递归,不可中断 | 异步迭代,可中断/恢复 |
优先级支持 | 无 | 支持动态优先级调度 |
性能表现 | 复杂树渲染易卡顿 | 分片渲染,保持 UI 响应 |
适用场景 | 简单应用 | 大型/复杂应用 |
四、总结
React Fiber 通过 增量渲染 和 优先级调度 实现高效的任务管理,其核心优势在于:
• 响应性提升:避免长时间阻塞主线程,保障交互流畅。
• 性能优化:仅更新实际变化的部分,减少计算开销。
• 扩展性增强:支持并发模式(Concurrent Mode)和错误边界等高级特性。
通过这种设计,React Fiber 成为现代 Web 应用高性能渲染的基石。