在renderRootSync执行完render相关阶段后,就会进入commit阶段。performSyncWorkOnRoot函数执行的末尾调用commitRoot(root);
commit阶段工作
在 rootFiber.firstEffect 上保存了一条需要执行副作用的 Fiber 节点的单向链表effectList,这些 Fiber 节点的 updateQueue 中保存了变化的 props。
除此之外,一些生命周期钩子(比如 componentDidXXX)、hook(比如 useEffect)需要在commit 阶段执行。
commit 阶段的主要工作分为三部分:
- before mutation 阶段(执行 DOM 操作前)
- mutation 阶段(执行 DOM 操作)
- layout 阶段(执行 DOM 操作后)
commitRoot
commit阶段工作起点,把fiberNode传参进去
function commitRoot(root) {
// getCurrentPriorityLevel调度优先级相关
const renderPriorityLevel = getCurrentPriorityLevel();
runWithPriority(
ImmediateSchedulerPriority,
commitRootImpl.bind(null, root, renderPriorityLevel),
);
return null;
}
commitRootImpl
代码300多行, 主要包括commit的前置工作和上文三阶段的执行,下面代码主要是前置部分
commit阶段前置工作:
- 调用flushPassiveEffects执行完所有effect的任务
- 初始化相关变量
赋值firstEffect给后面遍历effectList用
function commitRootImpl(root, renderPriorityLevel) { do { // 触发 useEffect 回调与其他同步任务。由于这些任务可能触发新的渲染,所以这里要一直遍历执行直到没有任务 flushPassiveEffects(); } while (rootWithPendingPassiveEffects !== null); // 指向当前应用的rootFiber const finishedWork = root.finishedWork; // 优先级 const lanes = root.finishedLanes; if (finishedWork === null) { return null; } // 重置变量 root.finishedWork = null; root.finishedLanes = NoLanes; // Scheduler回调函数重置 root.callbackNode = null; root.callbackId = NoLanes; // 合并和清除优先级 let remainingLanes = mergeLanes(finishedWork.lanes, finishedWork.childLanes); markRootFinished(root, remainingLanes); // 清除已完成的discrete updates,例如:用户鼠标点击触发的更新。 if (rootsWithPendingDiscreteUpdates !== null) { if ( !hasDiscreteLanes(remainingLanes) && rootsWithPendingDiscreteUpdates.has(root) ) { rootsWithPendingDiscreteUpdates.delete(root); } } // 重置全局变量 if (root === workInProgressRoot) { workInProgressRoot = null; workInProgress = null; workInProgressRootRenderLanes = NoLanes; } else { } // 将effectList副作用赋值给firstEffect let firstEffect; if (finishedWork.effectTag > PerformedWork) { if (finishedWork.lastEffect !== null) { finishedWork.lastEffect.nextEffect = finishedWork; firstEffect = finishedWork.firstEffect; } else { firstEffect = finishedWork; } } else { firstEffect = finishedWork.firstEffect; } }
flushPassiveEffects
先设置优先级然后调用flushPassiveEffectsImpl,执行所有effect的任务
function flushPassiveEffects() {
if (pendingPassiveEffectsRenderPriority !== NoSchedulerPriority) {
const priorityLevel =
pendingPassiveEffectsRenderPriority > NormalSchedulerPriority
? NormalSchedulerPriority
: pendingPassiveEffectsRenderPriority;
pendingPassiveEffectsRenderPriority = NoSchedulerPriority;
const previousLanePriority = getCurrentUpdateLanePriority();
try {
setCurrentUpdateLanePriority(
schedulerPriorityToLanePriority(priorityLevel),
);
return runWithPriority(priorityLevel, flushPassiveEffectsImpl);
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
}
}
}
总结
- 这一章主要看了commitRootImpl函数部分代码
- 了解commmit阶段的前置工作
了解到有三个不一样的函数执行流程:
- before mutation 阶段(执行 DOM 操作前)
- mutation 阶段(执行 DOM 操作)
- layout 阶段(执行 DOM 操作后)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。