# workLoopSync
前面已经讲过在 performSyncWorkOnRoot 分别会调用 workLoopSync 和 finishSyncRender 我们先从 开始
function workLoopSync() {
// 1. 处理了一个Fiber, 返回下一个fiber,
// 采用深度优先遍历,先找child,sibling fiber
while (workInProgress !== null) {
workInProgress = performUnitOfWork(workInProgress);
}
}
2
3
4
5
6
7
这个地方就是一个 while 循环调用 performUnitOfWork 传入我们之前生成的 workInProgress
# performUnitOfWork
function performUnitOfWork(unitOfWork: Fiber): Fiber | null {
// 第一次render时, unitOfWork=HostRootFiber, alternate已经初始化
const current = unitOfWork.alternate;
// current.alternate => 上一次构建的这个Fiber节点
startWorkTimer(unitOfWork);
setCurrentDebugFiberInDEV(unitOfWork);
let next;
if (enableProfilerTimer && (unitOfWork.mode & ProfileMode) !== NoMode) {
startProfilerTimer(unitOfWork);
next = beginWork(current, unitOfWork, renderExpirationTime);
stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true);
} else {
// 创建Fiber节点, 打上了EffectTag标志
next = beginWork(current, unitOfWork, renderExpirationTime);
}
resetCurrentDebugFiberInDEV();
unitOfWork.memoizedProps = unitOfWork.pendingProps;
// 没有next,意味着fiber tree已经构建完毕了
if (next === null) {
next = completeUnitOfWork(unitOfWork);
}
ReactCurrentOwner.current = null;
return next;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
performUnitOfWork 对传入的 workInProgress Fiber 节点进行深度优先循环处理
- 调用 beginWork
- 创建 FiberNode, 打上 EffectTag 标记
- 深度优先遍历
- 如果 fiber 创建完了,调用 completeUnitOfWork
# 流程概览
上面这些可以把流程简化,如下:
function workLoop(deadline) {
let shouldYield = false; // 是否让出时间片或者控制权
while (nextUnitOfWork && !shouldYield) {
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
shouldYield = deadline.timeRemaining() < 1; //没有时间了,就要让出控制权
}
//如果时间片到期了还有任务没有完成,就需要请求浏览器再次调度
if (!nextUnitOfWork && workInProgressRoot) {
console.log("render阶段结束");
//完成之后提交
commitRoot();
}
// 每一帧都要执行
window.requestIdleCallback(workLoop, { timeout: 500 });
}
function performUnitOfWork(workInProgress) {
let next = beginWork(current, workInProgress);
if (next === null) {
next = completeUnitOfWork(workInProgress);
}
return next;
}
window.requestIdleCallback(workLoop, { timeout: 500 });
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
performUnitOfWork 方法会创建下一个 Fiber 节点并赋值给 workInProgress,并将 workInProgress 与已创建的 Fiber 节点连接起来构成 Fiber 树。在 React 中自己实现了 requestIdleCallback,这样就实现了可中断的递归,所以 performUnitOfWork 的工作可以分为两部分:递和归
# 递阶段
首先从 rootFiber 开始向下深度优先遍历。为遍历到的每个 Fiber 节点调用 beginWork (opens new window)方法。
该方法会根据传入的 Fiber 节点创建子 Fiber 节点,并将这两个 Fiber 节点连接起来。
当遍历到叶子节点(即没有子组件的组件)时就会进入“归”阶段。
# 归阶段
在归阶段会调用 completeWork (opens new window)处理 Fiber 节点。
当某个 Fiber 节点执行完 completeWork,如果其存在兄弟 Fiber 节点(即 fiber.sibling !== null),会进入其兄弟 Fiber 的 递 阶段。
如果不存在兄弟 Fiber , 会进入父级 Fiber 的“归”阶段。
“递”和“归”阶段会交错执行直到“归”到 rootFiber。至此,render 阶段的工作就结束了。
# 例子
如下的 jsx 会生成以下的 fiber 结构
function App() {
return (
<div>
i am
<span>KaSong</span>
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
2
3
4
5
6
7
8
9
10
对应的 Fiber 树结构:

这个结构刚好对应我们之前说的 Fiber 的数据结构
render 阶段会依次执行:
1. rootFiber beginWork
2. App Fiber beginWork
3. div Fiber beginWork
4. "i am" Fiber beginWork
5. "i am" Fiber completeWork
6. span Fiber beginWork
7. span Fiber completeWork
8. div Fiber completeWork
9. App Fiber completeWork
10. rootFiber completeWork
注意
React 只会在这个节点有兄弟节点的时候会创建 fiber 为独生子的时候不会创建 fiber 直接返回 null,这是 React 的一个性能优化
# 总结
React 会根据 jsx 编译生成的数据结构 生成 Fiber 树, 在创建过程中会从根到底生成,然后再回到根节点。 在此过程中会调用 beginWork 和 completeWork 后面再具体分析这两个方法如何工作的
← 双缓存 fiber 树 beginWork →