4

React commit阶段解析-前置学习

 2 years ago
source link: https://segmentfault.com/a/1190000040853854
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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

commit阶段工作

在 rootFiber.firstEffect 上保存了一条需要执行副作用的 Fiber 节点的单向链表effectList,这些 Fiber 节点的 updateQueue 中保存了变化的 props。

这些副作用对应的 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 操作后)

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK