React commit阶段解析-前置学习

在renderRootSync执行完render相关阶段后,就会进入commit阶段。performSyncWorkOnRoot函数执行的末尾调用commitRoot(root);
commit阶段工作

在 rootFiber.firstEffect 上保存了一条需要执行副作用的 Fiber 节点的单向链表effectList,这些 Fiber 节点的 updateQueue 中保存了变化的 props。
【React commit阶段解析-前置学习】这些副作用对应的 DOM 操作在commit 阶段执行。
除此之外,一些生命周期钩子(比如 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); } } }

总结
  1. 这一章主要看了commitRootImpl函数部分代码
  2. 了解commmit阶段的前置工作
  3. 了解到有三个不一样的函数执行流程:
    • before mutation 阶段(执行 DOM 操作前)
    • mutation 阶段(执行 DOM 操作)
    • layout 阶段(执行 DOM 操作后)

    推荐阅读