Appearance
在执行
FiberNode
的completeWork
之后,进入commit
阶段,开始渲染
js
function performSyncWorkOnRoot() {
//...
const finishedWork = root.current.alternate;
root.finishedWork = finishedWork;
root.finishedLanes = lanes;
commitRoot(root);
ensureRootIsScheduled(root, now());
}
function commitRoot(root) {
const renderPriorityLevel = getCurrentPriorityLevel(); // 调度优先级
runWithPriority(
ImmediateSchedulerPriority,
commitRootImpl.bind(null, root, renderPriorityLevel),
);
// 最终调用 commitRootImpl
return null;
}
function commitRootImpl(root, renderPriorityLevel) {
do {
// 执行在本次 commit 之前没有执行的 useEffect回调和其他同步任务
// 由于这些任务回调可能触发新的渲染,因此使用循环
flushPassiveEffects();
} while(rootWithPendingPassiveEffects !== null);
const finishedWork = root.finishedWork;
// 凡是变量名带lane的都是优先级相关
const lanes = root.finishedLanes;
if (finishedWork === null) {
return null;
}
root.finishedWork = null;
root.finishedLanes = NoLanes;
// 重置Scheduler绑定的回调函数
root.callbackNode = null;
root.callbackId = NoLanes;
// 清除已完成的discrete updates,例如:用户鼠标点击触发的更新。
if (rootsWithPendingDiscreteUpdates !== null) {
if (
!hasDiscreteLanes(remainingLanes) &&
rootsWithPendingDiscreteUpdates.has(root)
) {
rootsWithPendingDiscreteUpdates.delete(root);
}
}
// 重置全局变量
if (root === workInProgressRoot) {
workInProgressRoot = null;
workInProgress = null;
workInProgressRootRenderLanes = NoLanes;
}
// 将effectList赋值给firstEffect
// 由于每个fiber的effectList只包含他的子孙节点
// 所以根节点如果有flags则不会被包含进来
// 所以这里将有flags的根节点插入到effectList尾部
// 这样才能保证有effect的fiber都在effectList中
let firstEffect;
if (finishedWork.flags > PerformedWork) {
if (finishedWork.lastEffect !== null) {
finishedWork.lastEffect.nextEffect = finishedWork;
firstEffect = finishedWork.firstEffect;
} else {
firstEffect = finishedWork;
}
} else {
// 根节点没有flags
firstEffect = finishedWork.firstEffect;
}
//... before mutation阶段(执行`DOM`操作前)
nextEffect = firstEffect;
do{
commitBeforeMutationEffects()
} while(nextEffect !== null);
// mutation阶段(执行`DOM`操作)
nextEffect = firstEffect;
do{
commitMutationEffects()
} while(nextEffect !== null);
// layout阶段(执行`DOM`操作后)
nextEffect = firstEffect;
do{
commitLayoutEffects()
} while(nextEffect !== null);
// ... 最后调度root,由于commit阶段可能产生新的更新
ensureRootIsScheduled(root, now());
// 执行同步任务,这样同步任务不需要等到下次事件循环再执行
// 比如在 componentDidMount 中执行 setState 创建的更新会在这里被同步执行
// 或useLayoutEffect
flushSyncCallbackQueue();
return null
}