Appearance
Fiber架构原理
第一部分:Fiber架构概述
1.1 什么是Fiber
Fiber是React 16引入的全新协调(Reconciliation)引擎架构,是React核心算法的完全重写。Fiber使React能够将渲染工作分割成多个小块,并在多个帧之间分配渲染工作,从而实现可中断的渲染过程。
核心特点:
- 可中断的渲染
- 优先级调度
- 增量渲染
- 并发模式支持
- 更好的错误处理
1.2 为什么需要Fiber
在React 15及之前的版本中,协调算法采用递归的方式,一旦开始就无法中断。这在处理大型组件树时会导致严重的性能问题。
React 15的问题:
javascript
// React 15的递归渲染
function reconcile(element) {
// 创建或更新DOM
updateDOM(element);
// 递归处理子元素
element.children.forEach(child => {
reconcile(child); // 无法中断
});
}
// 问题示例:
function HeavyComponent() {
const items = Array.from({ length: 10000 }, (_, i) => ({
id: i,
value: Math.random()
}));
// React 15中,这会阻塞主线程
return (
<div>
{items.map(item => (
<ExpensiveItem key={item.id} data={item} />
))}
</div>
);
}React 15存在的问题:
- 长时间占用主线程,导致页面卡顿
- 用户输入响应延迟
- 动画掉帧
- 无法按优先级处理更新
- 无法实现异步渲染
1.3 Fiber的设计目标
Fiber架构的核心目标是实现增量渲染,将渲染工作分解成块,并在多个帧之间分配。
主要目标:
- 暂停工作,稍后再回来
javascript
// 伪代码展示Fiber的工作方式
function workLoop(deadline) {
let shouldYield = false;
while (nextUnitOfWork && !shouldYield) {
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
shouldYield = deadline.timeRemaining() < 1;
}
if (nextUnitOfWork) {
// 还有工作要做,下一帧继续
requestIdleCallback(workLoop);
}
}- 为不同类型的工作分配优先级
javascript
// 优先级示例
const priorities = {
Immediate: 1, // 立即执行(如用户输入)
UserBlocking: 2, // 用户交互
Normal: 3, // 普通更新
Low: 4, // 低优先级
Idle: 5 // 空闲时执行
};- 复用之前完成的工作
javascript
// Fiber可以复用之前的工作结果
function reconcileChildren(fiber, children) {
let oldFiber = fiber.alternate?.child;
for (let i = 0; i < children.length; i++) {
const element = children[i];
if (oldFiber && oldFiber.type === element.type) {
// 复用现有Fiber
newFiber = {
...oldFiber,
props: element.props,
alternate: oldFiber
};
} else {
// 创建新Fiber
newFiber = createFiber(element);
}
oldFiber = oldFiber?.sibling;
}
}- 如果不再需要,可以中止工作
javascript
// 高优先级任务可以打断低优先级任务
function commitRoot() {
if (hasHigherPriorityWork()) {
// 放弃当前工作,处理高优先级任务
currentWork = null;
scheduleHighPriorityWork();
} else {
// 提交当前工作结果
commitAllWork(workInProgress);
}
}1.4 Fiber与传统React的对比
React 15 - 栈协调器(Stack Reconciler):
javascript
// React 15的工作方式
class StackReconciler {
reconcile(element) {
// 同步递归,无法中断
this.updateComponent(element);
element.children.forEach(child => {
this.reconcile(child);
});
}
// 问题:一旦开始就必须完成
render() {
this.reconcile(this.rootElement); // 阻塞
this.commitChanges(); // 阻塞
}
}React 16+ - Fiber协调器:
javascript
// Fiber的工作方式
class FiberReconciler {
workLoop(deadline) {
while (this.nextUnitOfWork && deadline.timeRemaining() > 0) {
// 每次只处理一个工作单元
this.nextUnitOfWork = this.performUnitOfWork(
this.nextUnitOfWork
);
}
if (this.nextUnitOfWork) {
// 下一帧继续
requestIdleCallback(this.workLoop);
} else if (this.pendingCommit) {
// 提交更改
this.commitAllWork(this.pendingCommit);
}
}
performUnitOfWork(fiber) {
// 1. 处理当前Fiber
this.beginWork(fiber);
// 2. 返回下一个工作单元
if (fiber.child) {
return fiber.child;
}
let nextFiber = fiber;
while (nextFiber) {
if (nextFiber.sibling) {
return nextFiber.sibling;
}
nextFiber = nextFiber.parent;
}
return null;
}
}第二部分:Fiber数据结构
2.1 Fiber节点结构
每个React元素都对应一个Fiber节点,Fiber节点是一个JavaScript对象,包含了组件的类型、props、state等信息。
Fiber节点的核心字段:
javascript
// Fiber节点的完整结构
interface Fiber {
// 节点类型信息
tag: WorkTag; // Fiber类型(函数组件、类组件等)
key: null | string; // React key
elementType: any; // 元素类型
type: any; // 组件类型或DOM标签
stateNode: any; // 关联的DOM节点或组件实例
// Fiber树结构
return: Fiber | null; // 父Fiber
child: Fiber | null; // 第一个子Fiber
sibling: Fiber | null; // 下一个兄弟Fiber
index: number; // 在兄弟中的索引
// 工作相关
pendingProps: any; // 新的props
memoizedProps: any; // 上次渲染的props
updateQueue: UpdateQueue; // 更新队列
memoizedState: any; // 上次渲染的state
// Effect相关
flags: Flags; // 副作用标记
subtreeFlags: Flags; // 子树副作用标记
deletions: Array<Fiber>; // 要删除的子Fiber
// 优先级调度
lanes: Lanes; // 当前Fiber的优先级
childLanes: Lanes; // 子树的优先级
// 双缓冲
alternate: Fiber | null; // 对应的另一棵树的Fiber
}示例代码展示Fiber结构:
javascript
// 示例组件
function App() {
const [count, setCount] = useState(0);
return (
<div className="app">
<h1>Count: {count}</h1>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
);
}
// 对应的Fiber树结构
const appFiber = {
type: App,
tag: FunctionComponent,
stateNode: null,
// Hook状态
memoizedState: {
memoizedState: 0, // count的值
next: null // 下一个Hook
},
// 子节点
child: {
type: 'div',
tag: HostComponent,
stateNode: divDOMNode,
props: {
className: 'app',
children: [...]
},
child: {
type: 'h1',
tag: HostComponent,
stateNode: h1DOMNode,
sibling: {
type: 'button',
tag: HostComponent,
stateNode: buttonDOMNode
}
}
}
};2.2 Fiber标签类型(WorkTag)
Fiber节点根据组件类型有不同的tag:
javascript
// Fiber标签类型
const WorkTag = {
FunctionComponent: 0, // 函数组件
ClassComponent: 1, // 类组件
IndeterminateComponent: 2, // 未确定的组件类型
HostRoot: 3, // 根节点
HostPortal: 4, // Portal
HostComponent: 5, // DOM原生组件(div、span等)
HostText: 6, // 文本节点
Fragment: 7, // Fragment
Mode: 8, // Mode组件(StrictMode等)
ContextConsumer: 9, // Context消费者
ContextProvider: 10, // Context提供者
ForwardRef: 11, // ForwardRef
Profiler: 12, // Profiler
SuspenseComponent: 13, // Suspense
MemoComponent: 14, // Memo
SimpleMemoComponent: 15, // Simple Memo
LazyComponent: 16, // Lazy
IncompleteClassComponent: 17,
DehydratedFragment: 18,
SuspenseListComponent: 19,
ScopeComponent: 21,
OffscreenComponent: 22,
LegacyHiddenComponent: 23,
CacheComponent: 24,
TracingMarkerComponent: 25
};
// 使用示例
function createFiberFromElement(element) {
let fiberTag;
const { type } = element;
if (typeof type === 'function') {
// 函数或类组件
fiberTag = type.prototype?.isReactComponent
? WorkTag.ClassComponent
: WorkTag.FunctionComponent;
} else if (typeof type === 'string') {
// DOM元素
fiberTag = WorkTag.HostComponent;
} else if (type === REACT_FRAGMENT_TYPE) {
fiberTag = WorkTag.Fragment;
} else if (type === REACT_SUSPENSE_TYPE) {
fiberTag = WorkTag.SuspenseComponent;
}
// ... 其他类型
return createFiber(fiberTag, element.props, element.key);
}2.3 副作用标记(Flags)
Fiber使用flags字段标记需要执行的副作用:
javascript
// 副作用标记(Flags)
const Flags = {
NoFlags: 0, // 无副作用
PerformedWork: 1, // 已执行工作
Placement: 2, // 插入DOM
Update: 4, // 更新
Deletion: 8, // 删除
ChildDeletion: 16, // 删除子节点
ContentReset: 32, // 重置内容
Callback: 64, // 回调
DidCapture: 128, // 捕获错误
ForceClientRender: 256, // 强制客户端渲染
Ref: 512, // Ref更新
Snapshot: 1024, // Snapshot
Passive: 2048, // Passive effect(useEffect)
Hydrating: 4096, // Hydrating
Visibility: 8192, // 可见性变化
StoreConsistency: 16384, // Store一致性
// 生命周期相关
LifecycleEffectMask: 2116, // 生命周期effect mask
HostEffectMask: 32767, // Host effect mask
// Suspense相关
Incomplete: 32768,
ShouldCapture: 65536,
// 其他
ForceUpdateForLegacySuspense: 131072,
DidPropagateContext: 262144,
NeedsPropagation: 524288,
Forked: 1048576
};
// 使用示例
function markUpdate(fiber) {
fiber.flags |= Flags.Update;
}
function markPlacement(fiber) {
fiber.flags |= Flags.Placement;
}
function markDeletion(parentFiber, childFiber) {
parentFiber.flags |= Flags.ChildDeletion;
parentFiber.deletions = parentFiber.deletions || [];
parentFiber.deletions.push(childFiber);
}
// 检查标记
function hasEffect(fiber, flag) {
return (fiber.flags & flag) !== Flags.NoFlags;
}
// 完整示例
function completeWork(fiber) {
switch (fiber.tag) {
case HostComponent: {
if (fiber.stateNode == null) {
// 创建DOM节点
const instance = createInstance(fiber.type, fiber.props);
fiber.stateNode = instance;
markPlacement(fiber); // 标记为插入
} else {
// 更新DOM节点
const instance = fiber.stateNode;
prepareUpdate(instance, fiber.type, fiber.memoizedProps, fiber.pendingProps);
markUpdate(fiber); // 标记为更新
}
break;
}
// ... 其他case
}
}2.4 优先级通道(Lanes)
Lanes是Fiber中用于表示优先级的位掩码系统:
javascript
// Lanes优先级系统
const Lanes = {
NoLanes: 0,
NoLane: 0,
// 同步优先级
SyncLane: 1, // 同步(最高优先级)
// 连续事件优先级
InputContinuousHydrationLane: 2,
InputContinuousLane: 4,
// 默认优先级
DefaultHydrationLane: 8,
DefaultLane: 16,
// Transition优先级
TransitionHydrationLane: 32,
TransitionLane1: 64,
TransitionLane2: 128,
TransitionLane3: 256,
// ... 更多Transition lanes
// Retry优先级
RetryLane1: 134217728,
RetryLane2: 268435456,
RetryLane3: 536870912,
RetryLane4: 1073741824,
// 其他
SomeRetryLane: 2013265920,
SelectiveHydrationLane: 2147483648,
// 空闲优先级
IdleHydrationLane: 1073741824,
IdleLane: 2147483648,
// Offscreen
OffscreenLane: 4294967296
};
// Lane操作工具函数
function mergeLanes(a, b) {
return a | b;
}
function removeLanes(set, subset) {
return set & ~subset;
}
function includesSomeLane(a, b) {
return (a & b) !== NoLanes;
}
function isSubsetOfLanes(set, subset) {
return (set & subset) === subset;
}
// 获取最高优先级Lane
function getHighestPriorityLane(lanes) {
return lanes & -lanes;
}
// 示例:计算更新优先级
function requestUpdateLane(fiber) {
const mode = fiber.mode;
if ((mode & ConcurrentMode) === NoMode) {
return SyncLane; // 非并发模式,同步更新
}
// 检查是否在Transition中
if (currentTransition !== null) {
return claimNextTransitionLane();
}
// 检查事件优先级
const updateLane = getCurrentUpdateLane();
if (updateLane !== NoLane) {
return updateLane;
}
// 默认优先级
return DefaultLane;
}
// 完整示例:处理不同优先级的更新
function scheduleUpdateOnFiber(fiber, lane) {
// 1. 标记Fiber的lanes
fiber.lanes = mergeLanes(fiber.lanes, lane);
// 2. 向上标记父Fiber的childLanes
let node = fiber.return;
while (node !== null) {
node.childLanes = mergeLanes(node.childLanes, lane);
node = node.return;
}
// 3. 调度更新
if (lane === SyncLane) {
// 同步更新
scheduleSyncCallback(performSyncWorkOnRoot.bind(null, fiber));
} else {
// 异步更新
scheduleCallback(
lanePriorityToSchedulerPriority(lane),
performConcurrentWorkOnRoot.bind(null, fiber)
);
}
}第三部分:Fiber工作原理
3.1 双缓冲技术
Fiber使用双缓冲技术在内存中构建新的Fiber树,完成后再替换当前树。
javascript
// 双缓冲Fiber树
let currentRoot = null; // 当前显示的Fiber树
let workInProgressRoot = null; // 正在构建的Fiber树
// 创建WorkInProgress树
function createWorkInProgress(current, pendingProps) {
let workInProgress = current.alternate;
if (workInProgress === null) {
// 首次渲染,创建新的Fiber
workInProgress = createFiber(
current.tag,
pendingProps,
current.key
);
workInProgress.elementType = current.elementType;
workInProgress.type = current.type;
workInProgress.stateNode = current.stateNode;
// 建立双向连接
workInProgress.alternate = current;
current.alternate = workInProgress;
} else {
// 复用现有Fiber
workInProgress.pendingProps = pendingProps;
workInProgress.type = current.type;
// 重置副作用
workInProgress.flags = NoFlags;
workInProgress.subtreeFlags = NoFlags;
workInProgress.deletions = null;
}
// 复制其他字段
workInProgress.childLanes = current.childLanes;
workInProgress.lanes = current.lanes;
workInProgress.child = current.child;
workInProgress.memoizedProps = current.memoizedProps;
workInProgress.memoizedState = current.memoizedState;
workInProgress.updateQueue = current.updateQueue;
return workInProgress;
}
// 完整的双缓冲流程
function performConcurrentWorkOnRoot(root) {
// 1. 创建WorkInProgress树
workInProgressRoot = createWorkInProgress(root.current, null);
// 2. 开始渲染阶段
renderRootConcurrent(root, lanes);
// 3. 完成渲染,准备提交
const finishedWork = workInProgressRoot;
// 4. 提交阶段
commitRoot(finishedWork);
// 5. 切换current指针
root.current = finishedWork;
currentRoot = finishedWork;
workInProgressRoot = null;
}双缓冲可视化:
javascript
// 初始状态
// current树(屏幕显示)
const currentTree = {
type: 'div',
props: { className: 'old' },
stateNode: domNode,
alternate: null
};
// 第一次更新
// 1. 创建workInProgress树
const workInProgressTree = {
type: 'div',
props: { className: 'new' }, // 新props
stateNode: domNode, // 复用DOM
alternate: currentTree // 指向current
};
currentTree.alternate = workInProgressTree;
// 2. 在workInProgress上工作(可中断)
performUnitOfWork(workInProgressTree);
// 3. 提交完成,切换指针
root.current = workInProgressTree;
// 第二次更新
// workInProgress和current角色互换
const newWorkInProgress = currentTree; // 复用之前的current
newWorkInProgress.props = { className: 'newer' };3.2 Fiber工作循环
Fiber的工作循环分为两个主要阶段:render阶段和commit阶段。
Render阶段(可中断):
javascript
// Render阶段工作循环
function workLoopConcurrent() {
// 当有工作单元且未超时时继续
while (workInProgress !== null && !shouldYield()) {
performUnitOfWork(workInProgress);
}
}
function workLoopSync() {
// 同步模式:一次性完成
while (workInProgress !== null) {
performUnitOfWork(workInProgress);
}
}
// 执行工作单元
function performUnitOfWork(unitOfWork) {
const current = unitOfWork.alternate;
// 1. 开始工作(beginWork)
let next = beginWork(current, unitOfWork, renderLanes);
// 2. 更新memoizedProps
unitOfWork.memoizedProps = unitOfWork.pendingProps;
if (next === null) {
// 3. 没有子节点,完成当前工作
completeUnitOfWork(unitOfWork);
} else {
// 4. 有子节点,继续处理
workInProgress = next;
}
}
// beginWork - 处理Fiber节点
function beginWork(current, workInProgress, renderLanes) {
// 根据tag类型处理
switch (workInProgress.tag) {
case FunctionComponent: {
return updateFunctionComponent(
current,
workInProgress,
workInProgress.type,
workInProgress.pendingProps,
renderLanes
);
}
case ClassComponent: {
return updateClassComponent(
current,
workInProgress,
workInProgress.type,
workInProgress.pendingProps,
renderLanes
);
}
case HostComponent: {
return updateHostComponent(
current,
workInProgress,
renderLanes
);
}
// ... 其他类型
}
}
// completeWork - 完成Fiber节点
function completeUnitOfWork(unitOfWork) {
let completedWork = unitOfWork;
do {
const current = completedWork.alternate;
const returnFiber = completedWork.return;
// 完成当前Fiber
completeWork(current, completedWork, renderLanes);
const siblingFiber = completedWork.sibling;
if (siblingFiber !== null) {
// 有兄弟节点,处理兄弟
workInProgress = siblingFiber;
return;
}
// 回到父节点
completedWork = returnFiber;
workInProgress = completedWork;
} while (completedWork !== null);
}Commit阶段(不可中断):
javascript
// Commit阶段 - 同步执行,不可中断
function commitRoot(root) {
const finishedWork = root.finishedWork;
const lanes = root.finishedLanes;
// 阶段1:before mutation
commitBeforeMutationEffects(finishedWork);
// 阶段2:mutation(DOM操作)
commitMutationEffects(finishedWork, root);
// 切换current树
root.current = finishedWork;
// 阶段3:layout
commitLayoutEffects(finishedWork, lanes);
// 请求绘制
requestPaint();
}
// Before Mutation阶段
function commitBeforeMutationEffects(finishedWork) {
while (nextEffect !== null) {
const fiber = nextEffect;
// 处理Snapshot effect(getSnapshotBeforeUpdate)
if ((fiber.flags & Snapshot) !== NoFlags) {
commitBeforeMutationEffectOnFiber(fiber);
}
nextEffect = nextEffect.nextEffect;
}
}
// Mutation阶段
function commitMutationEffects(finishedWork, root) {
while (nextEffect !== null) {
const fiber = nextEffect;
const flags = fiber.flags;
// 重置文本内容
if (flags & ContentReset) {
commitResetTextContent(fiber);
}
// 处理Ref
if (flags & Ref) {
const current = fiber.alternate;
if (current !== null) {
commitDetachRef(current);
}
}
// 主要DOM操作
const primaryFlags = flags & (Placement | Update | Deletion | Hydrating);
switch (primaryFlags) {
case Placement: {
commitPlacement(fiber);
fiber.flags &= ~Placement;
break;
}
case Update: {
const current = fiber.alternate;
commitWork(current, fiber);
break;
}
case Deletion: {
commitDeletion(root, fiber);
break;
}
// ...
}
nextEffect = nextEffect.nextEffect;
}
}
// Layout阶段
function commitLayoutEffects(finishedWork, lanes) {
while (nextEffect !== null) {
const fiber = nextEffect;
const flags = fiber.flags;
// 处理Layout effect
if (flags & (Update | Callback)) {
commitLayoutEffectOnFiber(fiber, lanes);
}
// 绑定Ref
if (flags & Ref) {
commitAttachRef(fiber);
}
nextEffect = nextEffect.nextEffect;
}
}3.3 Fiber遍历算法
Fiber树采用深度优先遍历:
javascript
// Fiber树遍历
function traverseFiber(fiber) {
// 1. 处理当前节点
console.log('处理:', fiber.type);
// 2. 遍历子节点(深度优先)
if (fiber.child) {
traverseFiber(fiber.child);
}
// 3. 遍历兄弟节点
if (fiber.sibling) {
traverseFiber(fiber.sibling);
}
}
// 示例:组件树
function App() {
return (
<div>
<Header />
<Main>
<Article />
<Sidebar />
</Main>
<Footer />
</div>
);
}
// Fiber树结构和遍历顺序
const fiberTree = {
type: App,
child: {
type: 'div',
child: {
type: Header, // 1
sibling: {
type: Main, // 2
child: {
type: Article, // 3
sibling: {
type: Sidebar // 4
}
},
sibling: {
type: Footer // 5
}
}
}
}
};
// 遍历顺序:App -> div -> Header -> Main -> Article -> Sidebar -> Footer迭代式遍历(Fiber的实际实现):
javascript
// 非递归的Fiber遍历
function iterativeFiberTraversal(root) {
let node = root;
while (true) {
// 处理当前节点
performWork(node);
// 如果有子节点,进入子节点
if (node.child) {
node = node.child;
continue;
}
// 没有子节点,完成当前节点
if (node === root) {
return; // 遍历完成
}
// 找下一个兄弟节点或返回父节点
while (!node.sibling) {
if (!node.return || node.return === root) {
return; // 遍历完成
}
node = node.return;
}
node = node.sibling;
}
}
// 可中断的工作循环
function workLoop(deadline) {
while (nextUnitOfWork && deadline.timeRemaining() > 1) {
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
}
if (nextUnitOfWork) {
// 还有工作,下一帧继续
requestIdleCallback(workLoop);
}
}3.4 更新队列(Update Queue)
Fiber使用更新队列管理状态更新:
javascript
// 更新对象结构
interface Update<State> {
lane: Lane; // 优先级
tag: UpdateTag; // 更新类型
payload: any; // 更新内容
callback: (() => mixed) | null; // 回调函数
next: Update<State> | null; // 下一个更新
}
// 更新队列结构
interface UpdateQueue<State> {
baseState: State; // 基础state
firstBaseUpdate: Update<State> | null; // 第一个基础更新
lastBaseUpdate: Update<State> | null; // 最后一个基础更新
shared: {
pending: Update<State> | null; // 待处理的更新(环形链表)
};
effects: Array<Update<State>> | null; // 有回调的更新
}
// 创建更新
function createUpdate(lane) {
return {
lane,
tag: UpdateState,
payload: null,
callback: null,
next: null
};
}
// 入队更新
function enqueueUpdate(fiber, update) {
const updateQueue = fiber.updateQueue;
if (updateQueue === null) {
return;
}
const sharedQueue = updateQueue.shared;
const pending = sharedQueue.pending;
if (pending === null) {
// 第一个更新,创建环形链表
update.next = update;
} else {
// 插入到环形链表中
update.next = pending.next;
pending.next = update;
}
sharedQueue.pending = update;
}
// 处理更新队列
function processUpdateQueue(workInProgress, props, instance, renderLanes) {
const queue = workInProgress.updateQueue;
let firstBaseUpdate = queue.firstBaseUpdate;
let lastBaseUpdate = queue.lastBaseUpdate;
// 检查是否有待处理的更新
let pendingQueue = queue.shared.pending;
if (pendingQueue !== null) {
queue.shared.pending = null;
// 将pending队列接入base队列
const lastPendingUpdate = pendingQueue;
const firstPendingUpdate = lastPendingUpdate.next;
lastPendingUpdate.next = null;
if (lastBaseUpdate === null) {
firstBaseUpdate = firstPendingUpdate;
} else {
lastBaseUpdate.next = firstPendingUpdate;
}
lastBaseUpdate = lastPendingUpdate;
}
// 处理更新
if (firstBaseUpdate !== null) {
let newState = queue.baseState;
let newBaseState = null;
let newFirstBaseUpdate = null;
let newLastBaseUpdate = null;
let update = firstBaseUpdate;
do {
const updateLane = update.lane;
if (!isSubsetOfLanes(renderLanes, updateLane)) {
// 优先级不够,跳过此更新
const clone = {
lane: updateLane,
tag: update.tag,
payload: update.payload,
callback: update.callback,
next: null
};
if (newLastBaseUpdate === null) {
newFirstBaseUpdate = newLastBaseUpdate = clone;
newBaseState = newState;
} else {
newLastBaseUpdate = newLastBaseUpdate.next = clone;
}
} else {
// 处理更新
if (newLastBaseUpdate !== null) {
const clone = {
lane: NoLane,
tag: update.tag,
payload: update.payload,
callback: update.callback,
next: null
};
newLastBaseUpdate = newLastBaseUpdate.next = clone;
}
// 计算新state
newState = getStateFromUpdate(
workInProgress,
queue,
update,
newState,
props,
instance
);
// 处理callback
const callback = update.callback;
if (callback !== null) {
workInProgress.flags |= Callback;
const effects = queue.effects;
if (effects === null) {
queue.effects = [update];
} else {
effects.push(update);
}
}
}
update = update.next;
if (update === null) {
break;
}
} while (true);
// 更新队列
if (newLastBaseUpdate === null) {
newBaseState = newState;
}
queue.baseState = newBaseState;
queue.firstBaseUpdate = newFirstBaseUpdate;
queue.lastBaseUpdate = newLastBaseUpdate;
workInProgress.memoizedState = newState;
}
}第四部分:Fiber与Hooks
4.1 Hook在Fiber中的存储
Hook信息存储在Fiber的memoizedState中,形成链表结构:
javascript
// Hook结构
interface Hook {
memoizedState: any; // Hook的state
baseState: any; // 基础state
baseQueue: Update | null; // 基础更新队列
queue: UpdateQueue | null; // 更新队列
next: Hook | null; // 下一个Hook
}
// Fiber存储Hook链表
const fiber = {
memoizedState: { // 第一个Hook(useState)
memoizedState: 0, // count值
baseState: 0,
queue: {...},
next: { // 第二个Hook(useEffect)
memoizedState: {
create: () => {...},
destroy: undefined,
deps: [count],
next: null,
tag: HookHasEffect
},
next: null // 最后一个Hook
}
}
};
// 示例组件
function Counter() {
const [count, setCount] = useState(0); // Hook 1
const [name, setName] = useState('React'); // Hook 2
useEffect(() => { // Hook 3
document.title = `${name}: ${count}`;
}, [name, count]);
const increment = useCallback(() => { // Hook 4
setCount(c => c + 1);
}, []);
return (
<div>
<h1>{name}: {count}</h1>
<button onClick={increment}>+1</button>
</div>
);
}
// 对应的Hook链表
const hookChain = {
// Hook 1: useState(0)
memoizedState: 0,
queue: {
pending: null,
dispatch: setCount
},
next: {
// Hook 2: useState('React')
memoizedState: 'React',
queue: {
pending: null,
dispatch: setName
},
next: {
// Hook 3: useEffect
memoizedState: {
tag: HookHasEffect | HookPassive,
create: () => { document.title = `${name}: ${count}`; },
destroy: undefined,
deps: ['React', 0],
next: null
},
queue: null,
next: {
// Hook 4: useCallback
memoizedState: increment,
queue: null,
next: null
}
}
}
};4.2 Hook的执行时机
javascript
// 渲染函数组件
function renderWithHooks(
current,
workInProgress,
Component,
props,
secondArg,
nextRenderLanes
) {
renderLanes = nextRenderLanes;
currentlyRenderingFiber = workInProgress;
// 重置Hook状态
workInProgress.memoizedState = null;
workInProgress.updateQueue = null;
// 设置Hook dispatcher
ReactCurrentDispatcher.current =
current === null || current.memoizedState === null
? HooksDispatcherOnMount // 首次渲染
: HooksDispatcherOnUpdate; // 更新渲染
// 调用组件函数
let children = Component(props, secondArg);
// 重置dispatcher
ReactCurrentDispatcher.current = ContextOnlyDispatcher;
renderLanes = NoLanes;
currentlyRenderingFiber = null;
return children;
}
// useState的实现
function useState(initialState) {
const dispatcher = resolveDispatcher();
return dispatcher.useState(initialState);
}
// Mount时的useState
function mountState(initialState) {
const hook = mountWorkInProgressHook();
if (typeof initialState === 'function') {
initialState = initialState();
}
hook.memoizedState = hook.baseState = initialState;
const queue = {
pending: null,
dispatch: null,
lastRenderedReducer: basicStateReducer,
lastRenderedState: initialState
};
hook.queue = queue;
const dispatch = (queue.dispatch = dispatchSetState.bind(
null,
currentlyRenderingFiber,
queue
));
return [hook.memoizedState, dispatch];
}
// Update时的useState
function updateState(initialState) {
return updateReducer(basicStateReducer, initialState);
}
// 创建Hook
function mountWorkInProgressHook() {
const hook = {
memoizedState: null,
baseState: null,
baseQueue: null,
queue: null,
next: null
};
if (workInProgressHook === null) {
// 第一个Hook
currentlyRenderingFiber.memoizedState = workInProgressHook = hook;
} else {
// 后续Hook
workInProgressHook = workInProgressHook.next = hook;
}
return workInProgressHook;
}
// 更新Hook
function updateWorkInProgressHook() {
let nextCurrentHook;
if (currentHook === null) {
const current = currentlyRenderingFiber.alternate;
nextCurrentHook = current?.memoizedState;
} else {
nextCurrentHook = currentHook.next;
}
let nextWorkInProgressHook;
if (workInProgressHook === null) {
nextWorkInProgressHook = currentlyRenderingFiber.memoizedState;
} else {
nextWorkInProgressHook = workInProgressHook.next;
}
if (nextWorkInProgressHook !== null) {
// 复用现有Hook
workInProgressHook = nextWorkInProgressHook;
currentHook = nextCurrentHook;
} else {
// 克隆current Hook
const newHook = {
memoizedState: nextCurrentHook.memoizedState,
baseState: nextCurrentHook.baseState,
baseQueue: nextCurrentHook.baseQueue,
queue: nextCurrentHook.queue,
next: null
};
if (workInProgressHook === null) {
currentlyRenderingFiber.memoizedState = workInProgressHook = newHook;
} else {
workInProgressHook = workInProgressHook.next = newHook;
}
currentHook = nextCurrentHook;
}
return workInProgressHook;
}4.3 Effect的执行机制
javascript
// Effect Hook结构
interface Effect {
tag: HookFlags; // Effect类型
create: () => (() => void) | void; // effect函数
destroy: (() => void) | void; // 清理函数
deps: Array<mixed> | null; // 依赖数组
next: Effect; // 下一个Effect(环形链表)
}
// Fiber的updateQueue存储Effect链表
const fiber = {
updateQueue: {
lastEffect: effect3, // 指向最后一个Effect
// Effect环形链表
// effect1 -> effect2 -> effect3 -> effect1
}
};
// useEffect实现
function mountEffect(create, deps) {
const hook = mountWorkInProgressHook();
const nextDeps = deps === undefined ? null : deps;
currentlyRenderingFiber.flags |= PassiveEffect;
hook.memoizedState = pushEffect(
HookHasEffect | HookPassive,
create,
undefined,
nextDeps
);
}
function updateEffect(create, deps) {
const hook = updateWorkInProgressHook();
const nextDeps = deps === undefined ? null : deps;
let destroy = undefined;
if (currentHook !== null) {
const prevEffect = currentHook.memoizedState;
destroy = prevEffect.destroy;
if (nextDeps !== null) {
const prevDeps = prevEffect.deps;
if (areHookInputsEqual(nextDeps, prevDeps)) {
// 依赖未变化,不执行effect
hook.memoizedState = pushEffect(
HookPassive,
create,
destroy,
nextDeps
);
return;
}
}
}
currentlyRenderingFiber.flags |= PassiveEffect;
hook.memoizedState = pushEffect(
HookHasEffect | HookPassive,
create,
destroy,
nextDeps
);
}
// 添加Effect到Fiber
function pushEffect(tag, create, destroy, deps) {
const effect = {
tag,
create,
destroy,
deps,
next: null
};
let componentUpdateQueue = currentlyRenderingFiber.updateQueue;
if (componentUpdateQueue === null) {
componentUpdateQueue = createFunctionComponentUpdateQueue();
currentlyRenderingFiber.updateQueue = componentUpdateQueue;
componentUpdateQueue.lastEffect = effect.next = effect;
} else {
const lastEffect = componentUpdateQueue.lastEffect;
if (lastEffect === null) {
componentUpdateQueue.lastEffect = effect.next = effect;
} else {
const firstEffect = lastEffect.next;
lastEffect.next = effect;
effect.next = firstEffect;
componentUpdateQueue.lastEffect = effect;
}
}
return effect;
}
// Commit阶段执行Effect
function commitPassiveEffects(finishedWork) {
// 1. 执行清理函数
commitPassiveUnmountEffects(finishedWork);
// 2. 执行effect函数
commitPassiveMountEffects(finishedWork);
}
function commitPassiveMountEffects(finishedWork) {
const updateQueue = finishedWork.updateQueue;
const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;
if (lastEffect !== null) {
const firstEffect = lastEffect.next;
let effect = firstEffect;
do {
if ((effect.tag & HookPassive) !== NoFlags &&
(effect.tag & HookHasEffect) !== NoFlags) {
// 执行effect
const create = effect.create;
effect.destroy = create();
}
effect = effect.next;
} while (effect !== firstEffect);
}
}第五部分:Fiber调度机制
5.1 时间切片(Time Slicing)
Fiber通过时间切片实现可中断的渲染:
javascript
// 检查是否应该让出控制权
function shouldYield() {
const currentTime = getCurrentTime();
if (currentTime >= deadline) {
// 当前帧时间用完
if (needsPaint || scheduling.isInputPending()) {
// 需要绘制或有用户输入
return true;
}
// 还有时间可以继续工作
return currentTime >= maxYieldInterval;
}
return false;
}
// 工作循环 - 并发模式
function workLoopConcurrent() {
while (workInProgress !== null && !shouldYield()) {
performUnitOfWork(workInProgress);
}
}
// 完整的调度流程
function performConcurrentWorkOnRoot(root) {
const originalCallbackNode = root.callbackNode;
// 1. 刷新同步工作
flushPassiveEffects();
// 2. 获取待处理的lanes
const lanes = getNextLanes(root, NoLanes);
if (lanes === NoLanes) {
return null;
}
// 3. 设置渲染优先级
const prevDispatcher = pushDispatcher();
const prevExecutionContext = executionContext;
executionContext |= RenderContext;
// 4. 准备fresh stack
prepareFreshStack(root, lanes);
// 5. 开始渲染循环
do {
try {
workLoopConcurrent();
break;
} catch (thrownValue) {
handleError(root, thrownValue);
}
} while (true);
// 6. 恢复上下文
popDispatcher(prevDispatcher);
executionContext = prevExecutionContext;
// 7. 检查是否完成
if (workInProgress !== null) {
// 还有工作未完成
return performConcurrentWorkOnRoot.bind(null, root);
} else {
// 工作完成,准备提交
const finishedWork = root.current.alternate;
root.finishedWork = finishedWork;
root.finishedLanes = lanes;
finishConcurrentRender(root, exitStatus, lanes);
}
return null;
}5.2 优先级调度
javascript
// Scheduler优先级
const ImmediatePriority = 1;
const UserBlockingPriority = 2;
const NormalPriority = 3;
const LowPriority = 4;
const IdlePriority = 5;
// Lane优先级转Scheduler优先级
function lanePriorityToSchedulerPriority(lanePriority) {
switch (lanePriority) {
case SyncLane:
case SyncBatchedLane:
return ImmediatePriority;
case InputContinuousLane:
return UserBlockingPriority;
case DefaultLane:
return NormalPriority;
case IdleLane:
return IdlePriority;
default:
return NormalPriority;
}
}
// 调度更新
function ensureRootIsScheduled(root, currentTime) {
const existingCallbackNode = root.callbackNode;
// 1. 标记过期的lanes
markStarvedLanesAsExpired(root, currentTime);
// 2. 获取下一个要处理的lane
const nextLanes = getNextLanes(
root,
root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes
);
if (nextLanes === NoLanes) {
// 没有工作要做
if (existingCallbackNode !== null) {
cancelCallback(existingCallbackNode);
}
root.callbackNode = null;
root.callbackPriority = NoLane;
return;
}
// 3. 获取最高优先级
const newCallbackPriority = getHighestPriorityLane(nextLanes);
const existingCallbackPriority = root.callbackPriority;
// 4. 检查是否需要新调度
if (existingCallbackPriority === newCallbackPriority) {
// 优先级相同,继续当前调度
return;
}
// 5. 取消现有调度
if (existingCallbackNode !== null) {
cancelCallback(existingCallbackNode);
}
// 6. 调度新任务
let newCallbackNode;
if (newCallbackPriority === SyncLane) {
// 同步优先级
scheduleSyncCallback(
performSyncWorkOnRoot.bind(null, root)
);
newCallbackNode = null;
} else {
// 异步优先级
const schedulerPriorityLevel = lanePriorityToSchedulerPriority(
newCallbackPriority
);
newCallbackNode = scheduleCallback(
schedulerPriorityLevel,
performConcurrentWorkOnRoot.bind(null, root)
);
}
root.callbackPriority = newCallbackPriority;
root.callbackNode = newCallbackNode;
}
// 完整示例:处理多个不同优先级的更新
function handleMultiplePriorityUpdates() {
const root = createRoot(container);
// 低优先级更新
startTransition(() => {
setHeavyData(computeHeavyData()); // Transition Lane
});
// 中优先级更新
setTimeout(() => {
setNormalData(data); // Default Lane
}, 100);
// 高优先级更新
onClick={() => {
setCount(count + 1); // Sync Lane
});
// Fiber会按优先级处理:
// 1. Sync Lane (onClick) - 立即处理
// 2. Default Lane (setTimeout) - 正常处理
// 3. Transition Lane (startTransition) - 可被打断
}5.3 饥饿问题处理
javascript
// 标记过期的lanes,防止低优先级任务饥饿
function markStarvedLanesAsExpired(root, currentTime) {
const pendingLanes = root.pendingLanes;
const suspendedLanes = root.suspendedLanes;
const pingedLanes = root.pingedLanes;
const expirationTimes = root.expirationTimes;
let lanes = pendingLanes;
while (lanes > 0) {
const index = pickArbitraryLaneIndex(lanes);
const lane = 1 << index;
const expirationTime = expirationTimes[index];
if (expirationTime === NoTimestamp) {
// 设置过期时间
if ((lane & suspendedLanes) === NoLanes ||
(lane & pingedLanes) !== NoLanes) {
expirationTimes[index] = computeExpirationTime(lane, currentTime);
}
} else if (expirationTime <= currentTime) {
// 已过期,升级为过期lane
root.expiredLanes |= lane;
}
lanes &= ~lane;
}
}
// 计算过期时间
function computeExpirationTime(lane, currentTime) {
switch (lane) {
case SyncLane:
case InputContinuousLane:
// 高优先级:250ms后过期
return currentTime + 250;
case DefaultLane:
// 默认优先级:5s后过期
return currentTime + 5000;
case IdleLane:
// 空闲优先级:永不过期
return NoTimestamp;
default:
// Transition:5s后过期
return currentTime + 5000;
}
}第六部分:Fiber性能优化
6.1 Bailout优化
Fiber会跳过不需要更新的组件:
javascript
// Bailout检查
function bailoutOnAlreadyFinishedWork(
current,
workInProgress,
renderLanes
) {
// 检查children是否需要更新
if (!includesSomeLane(renderLanes, workInProgress.childLanes)) {
// children也不需要更新,直接返回null
return null;
}
// children需要更新,克隆children
cloneChildFibers(current, workInProgress);
return workInProgress.child;
}
// 检查是否可以bailout
function checkScheduledUpdateOrContext(
current,
renderLanes
) {
const updateLanes = workInProgress.lanes;
if (includesSomeLane(updateLanes, renderLanes)) {
return false; // 有更新,不能bailout
}
// 检查context
if (current !== null) {
const context = current.dependencies;
if (context !== null && checkIfContextChanged(context)) {
return false; // context变化,不能bailout
}
}
return true; // 可以bailout
}
// 示例:React.memo + bailout
const ExpensiveComponent = React.memo(function ExpensiveComponent({ data }) {
console.log('Rendering ExpensiveComponent');
return (
<div>
{data.map(item => (
<Item key={item.id} value={item.value} />
))}
</div>
);
});
function App() {
const [count, setCount] = useState(0);
const [data] = useState(expensiveData); // 不变的数据
return (
<div>
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
{/*
data没变化,ExpensiveComponent会bailout
不会重新渲染
*/}
<ExpensiveComponent data={data} />
</div>
);
}6.2 优先级复用
javascript
// 复用之前计算的结果
function reuseFiber(fiber, pendingProps) {
const clone = createWorkInProgress(fiber, pendingProps);
clone.index = 0;
clone.sibling = null;
return clone;
}
// 示例:列表diff复用
function reconcileChildrenArray(
returnFiber,
currentFirstChild,
newChildren,
lanes
) {
let resultingFirstChild = null;
let previousNewFiber = null;
let oldFiber = currentFirstChild;
let lastPlacedIndex = 0;
let newIdx = 0;
let nextOldFiber = null;
// 第一轮遍历:复用相同位置的节点
for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) {
if (oldFiber.index > newIdx) {
nextOldFiber = oldFiber;
oldFiber = null;
} else {
nextOldFiber = oldFiber.sibling;
}
const newFiber = updateSlot(
returnFiber,
oldFiber,
newChildren[newIdx],
lanes
);
if (newFiber === null) {
if (oldFiber === null) {
oldFiber = nextOldFiber;
}
break;
}
if (shouldTrackSideEffects) {
if (oldFiber && newFiber.alternate === null) {
deleteChild(returnFiber, oldFiber);
}
}
lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx);
if (previousNewFiber === null) {
resultingFirstChild = newFiber;
} else {
previousNewFiber.sibling = newFiber;
}
previousNewFiber = newFiber;
oldFiber = nextOldFiber;
}
if (newIdx === newChildren.length) {
// 新children已经遍历完,删除剩余oldFiber
deleteRemainingChildren(returnFiber, oldFiber);
return resultingFirstChild;
}
if (oldFiber === null) {
// oldFiber已遍历完,创建剩余新节点
for (; newIdx < newChildren.length; newIdx++) {
const newFiber = createChild(returnFiber, newChildren[newIdx], lanes);
if (newFiber === null) continue;
lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx);
if (previousNewFiber === null) {
resultingFirstChild = newFiber;
} else {
previousNewFiber.sibling = newFiber;
}
previousNewFiber = newFiber;
}
return resultingFirstChild;
}
// 将剩余oldFiber加入Map
const existingChildren = mapRemainingChildren(returnFiber, oldFiber);
// 第二轮遍历:处理移动的节点
for (; newIdx < newChildren.length; newIdx++) {
const newFiber = updateFromMap(
existingChildren,
returnFiber,
newIdx,
newChildren[newIdx],
lanes
);
if (newFiber !== null) {
if (shouldTrackSideEffects) {
if (newFiber.alternate !== null) {
existingChildren.delete(
newFiber.key === null ? newIdx : newFiber.key
);
}
}
lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx);
if (previousNewFiber === null) {
resultingFirstChild = newFiber;
} else {
previousNewFiber.sibling = newFiber;
}
previousNewFiber = newFiber;
}
}
if (shouldTrackSideEffects) {
// 删除未使用的oldFiber
existingChildren.forEach(child => deleteChild(returnFiber, child));
}
return resultingFirstChild;
}6.3 批量更新
javascript
// 批量更新机制
let isBatchingUpdates = false;
let batchedUpdates = [];
function batchedUpdates(fn) {
const prevIsBatchingUpdates = isBatchingUpdates;
isBatchingUpdates = true;
try {
return fn();
} finally {
isBatchingUpdates = prevIsBatchingUpdates;
if (!isBatchingUpdates) {
flushSyncCallbackQueue();
}
}
}
// 自动批量更新示例
function handleClick() {
// React 18会自动批量这些更新
setCount(c => c + 1); // 不会立即重渲染
setFlag(f => !f); // 不会立即重渲染
setValue(v => v * 2); // 批量后一次性重渲染
}
// React 18之前需要手动批量
function handleClickLegacy() {
ReactDOM.unstable_batchedUpdates(() => {
setCount(c => c + 1);
setFlag(f => !f);
setValue(v => v * 2);
});
}
// 异步更新也会批量(React 18+)
async function handleAsyncClick() {
await fetchData();
// React 18会自动批量
setData(newData);
setLoading(false);
setError(null);
}第七部分:Fiber调试技巧
7.1 Fiber DevTools
javascript
// 在开发环境中访问Fiber
function inspectFiber(component) {
const fiber = component._reactInternals ||
component._reactInternalFiber;
console.log('Fiber节点:', fiber);
console.log('类型:', fiber.type);
console.log('Props:', fiber.memoizedProps);
console.log('State:', fiber.memoizedState);
console.log('Flags:', fiber.flags);
return fiber;
}
// 遍历Fiber树
function traverseFiberTree(fiber, depth = 0) {
const indent = ' '.repeat(depth);
console.log(`${indent}${fiber.type?.name || fiber.type || 'Host'}`);
if (fiber.child) {
traverseFiberTree(fiber.child, depth + 1);
}
if (fiber.sibling) {
traverseFiberTree(fiber.sibling, depth);
}
}
// 使用示例
function DebugComponent() {
useEffect(() => {
const fiber = inspectFiber(DebugComponent);
traverseFiberTree(fiber);
}, []);
return <div>Debug</div>;
}7.2 性能分析
javascript
// Profiler API
import { Profiler } from 'react';
function onRenderCallback(
id, // Profiler的id
phase, // "mount"或"update"
actualDuration, // 本次渲染耗时
baseDuration, // 理论最短耗时
startTime, // 开始时间
commitTime, // 提交时间
interactions // 交互集合
) {
console.log(`[${id}] ${phase}阶段`);
console.log(`实际耗时: ${actualDuration}ms`);
console.log(`基准耗时: ${baseDuration}ms`);
if (actualDuration > baseDuration * 1.5) {
console.warn('性能警告:渲染时间超过基准50%');
}
}
function App() {
return (
<Profiler id="App" onRender={onRenderCallback}>
<Header />
<Profiler id="Main" onRender={onRenderCallback}>
<Main />
</Profiler>
<Footer />
</Profiler>
);
}注意事项
1. Fiber架构的限制
Fiber虽然强大,但有一些限制:
1. 内存开销
- 每个元素都有对应的Fiber节点
- 双缓冲需要两倍内存
2. 调试复杂度
- 调用栈更深
- 异步渲染难以追踪
3. 学习曲线
- 概念复杂
- 源码难懂2. 最佳实践
javascript
// 1. 合理使用key
function List({ items }) {
return items.map(item => (
// 使用稳定的key帮助Fiber复用
<Item key={item.id} data={item} />
));
}
// 2. 避免在渲染中修改数据
function Component() {
const [items, setItems] = useState([]);
// ❌ 错误:在渲染中修改
items.push(newItem);
// ✅ 正确:使用setState
const addItem = () => {
setItems([...items, newItem]);
};
}
// 3. 合理使用memo避免不必要的渲染
const HeavyComponent = React.memo(function HeavyComponent({ data }) {
// 大量计算
return <div>{expensiveComputation(data)}</div>;
});3. 性能优化建议
javascript
// 1. 使用Transition标记非紧急更新
import { useTransition } from 'react';
function SearchResults() {
const [query, setQuery] = useState('');
const [results, setResults] = useState([]);
const [isPending, startTransition] = useTransition();
const handleChange = (e) => {
setQuery(e.target.value); // 紧急:立即更新输入框
startTransition(() => {
// 非紧急:可被打断的搜索
setResults(search(e.target.value));
});
};
return (
<>
<input value={query} onChange={handleChange} />
{isPending && <Spinner />}
<ResultsList results={results} />
</>
);
}
// 2. 使用useDeferredValue延迟更新
function Component() {
const [value, setValue] = useState('');
const deferredValue = useDeferredValue(value);
return (
<>
<input value={value} onChange={e => setValue(e.target.value)} />
<SlowList text={deferredValue} />
</>
);
}
// 3. 避免频繁的context更新
const ThemeContext = createContext();
function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
// 使用useMemo避免每次都创建新对象
const value = useMemo(() => ({ theme, setTheme }), [theme]);
return (
<ThemeContext.Provider value={value}>
{children}
</ThemeContext.Provider>
);
}常见问题
Q1: Fiber如何实现可中断的渲染?
A: Fiber将渲染工作分解为小的工作单元,每完成一个单元就检查是否需要让出控制权。通过requestIdleCallback或MessageChannel实现帧间调度。
Q2: 为什么需要双缓冲技术?
A: 双缓冲允许React在内存中构建新的UI树,完成后再一次性替换,避免渲染过程中的视觉闪烁,并且支持中断和恢复。
Q3: Lane和Priority有什么区别?
A: Lane是Fiber内部的优先级系统,使用位掩码表示。Priority是Scheduler的优先级。Lane会被转换为Priority进行任务调度。
Q4: Hook为什么不能在条件语句中使用?
A: Hook依赖调用顺序来匹配Fiber的memoizedState链表。条件调用会破坏顺序,导致状态错乱。
Q5: Fiber如何处理错误边界?
A: Fiber在catch错误后会查找最近的错误边界组件,执行其getDerivedStateFromError和componentDidCatch,然后从该点重新渲染。
Q6: 如何优化Fiber性能?
A: 主要方法包括:使用React.memo减少不必要渲染、合理使用key帮助diff、使用Transition标记低优先级更新、避免大量同步setState。
Q7: Fiber与虚拟DOM的关系?
A: Fiber是虚拟DOM的一种实现方式。每个Fiber节点对应一个虚拟DOM节点,但包含更多信息用于调度和协调。
Q8: 如何调试Fiber问题?
A: 使用React DevTools的Profiler、在组件上添加Profiler API收集性能数据、检查组件的_reactInternals属性查看Fiber节点。
Q9: Concurrent Mode对Fiber有什么影响?
A: Concurrent Mode充分利用了Fiber的可中断特性,允许React同时准备多个版本的UI,并根据优先级选择最合适的版本提交。
Q10: Fiber的未来发展方向?
A: React团队正在优化Fiber的性能,改进Suspense和Transition的体验,探索更细粒度的更新机制,以及更好的服务器组件支持。
总结
Fiber核心要点
1. 架构特点
✅ 可中断的协调过程
✅ 优先级调度
✅ 增量渲染
✅ 双缓冲技术
✅ 时间切片
2. 数据结构
✅ Fiber节点(类型、props、state、flags等)
✅ 树形结构(parent、child、sibling)
✅ 双向链接(current、alternate)
✅ 更新队列(update queue)
✅ Effect链表
3. 工作流程
✅ Render阶段(可中断)
✅ Commit阶段(不可中断)
✅ 双缓冲切换
✅ 优先级调度
✅ 批量更新
4. 性能优化
✅ Bailout跳过
✅ Fiber复用
✅ Lane优先级
✅ 时间切片
✅ 批量提交最佳实践
开发建议:
1. 理解Fiber工作原理,合理使用React特性
2. 使用Profiler分析性能瓶颈
3. 合理使用memo、useMemo、useCallback
4. 为列表项提供稳定的key
5. 使用Transition标记低优先级更新
6. 避免在渲染中产生副作用
7. 合理拆分组件粒度
8. 利用Concurrent特性提升用户体验Fiber架构是React实现高性能、可中断渲染的基石,深入理解Fiber有助于编写更高效的React应用。