likes
comments
collection
share

React18.2源码解析之初始化阶段(下)

作者站长头像
站长
· 阅读数 7

记录学习过程,如有错误欢迎指出

上一篇文章我们讲到了scheduleUpdateOnFiber函数,这篇文章将会结束初始化阶段

开始之前(必看)

React version 18.2.0

DEV代码可以忽略,下面正文我使用省略号就代表是dev相关的代码,包含hydrate字样的也请忽略,那是服务端渲染相关,望周知

我使用深度优先(🐶)的方式讲解:即遇到函数先进入函数,执行完函数后,又退回之前的函数.而不是在一个函数中讲完了再讲函数中执行的函数(希望能听懂我在说什么^v^)

因为使用了深度优先的方式讲解,耦合比较重,不建议跳着看

scheduleUpdateOnFiber(未完)

....
// 进入ensureRootIsScheduled函数
    ensureRootIsScheduled(root, eventTime);
....

ensureRootIsScheduled

function ensureRootIsScheduled(root: FiberRoot, currentTime: number) {
  const existingCallbackNode = root.callbackNode;

  // 用于将已经被其他工作“饿死”的lane标记为已过期,后面会避免使用已过期的 lane
  markStarvedLanesAsExpired(root, currentTime);

  /**
   * 调用getNextLanes获取下一个车道
   * 如果没有下一个车道了,即调用结果是 NoLanes, 则退出
   * 退出前执行 root.callbackNode = null和root.callbackPriority = NoLane
   */
  const nextLanes = getNextLanes(
    root,
    root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes,
  );
  
  // 执行NoLanes的情况
  if (nextLanes === NoLanes) {
    // Special case: There's nothing to work on.
    if (existingCallbackNode !== null) {
      cancelCallback(existingCallbackNode);
    }
    root.callbackNode = null;
    root.callbackPriority = NoLane;
    return;
  }
  
  // 获取最高优先度的车道
  //getHighestPriorityLane()作用:就是获取最高优先级的lane
  const newCallbackPriority = getHighestPriorityLane(nextLanes);
  
  .......
  
  
  //重点开始!!!!
  //重点开始!!!!
  //重点开始!!!!
  
   /*
    不管是performSyncWorkOnRoot还是performConcurrentWorkOnRoot,
    内部都有commit阶段,只是名称逻辑不一样
  */
  // 调度一个新任务
  let newCallbackNode;
  // 如果当前调度的任务是是一个 Scheduler 任务而不是一个“act”任务,则退出,重新调度“act”的队列
  if (newCallbackPriority === SyncLane) {
  // 如果过期,任务以同步优先级被调度
    if (root.tag === LegacyRoot) {
      if (__DEV__ && ReactCurrentActQueue.isBatchingLegacy !== null) {
        ReactCurrentActQueue.didScheduleLegacyUpdate = true;
      }
      // Legacy同步
      // 它内部执行的还是scheduleSyncCallback
      scheduleLegacySyncCallback(performSyncWorkOnRoot.bind(null, root));
    } else {
      // 同步
      // 执行的就是往syncQueue推入
      scheduleSyncCallback(performSyncWorkOnRoot.bind(null, root));
    }
    
    
    //进入scheduleSyncCallback()后就是render阶段了
    //将在篇文章讲解render阶段
    
    
    // 是否支持微任务
    if (supportsMicrotasks) {
      // 刷新微任务队列
      if (__DEV__ && ReactCurrentActQueue.current !== null) {
        ReactCurrentActQueue.current.push(flushSyncCallbacks);
      } else {
        scheduleMicrotask(() => {
          if (
            (executionContext & (RenderContext | CommitContext)) ===
            NoContext
          ) {
            // Note that this would still prematurely flush the callbacks
            // if this happens outside render or commit phase (e.g. in an event).
            flushSyncCallbacks();
          }
        });
      }
    } else {
      // 如果不支持微任务,那么使用cheduleCallback(ImmediateSchedulerPriority, flushSyncCallbacks);
      // flushSyncCallbacks用于刷新一下,因为是刚刚推入的
      scheduleCallback(ImmediateSchedulerPriority, flushSyncCallbacks);
    }
    // newCallbackNode 置 null
    newCallbackNode = null;
  } else {
    let schedulerPriorityLevel;
    // 将lanes优先级转为普通事件优先级
    switch (lanesToEventPriority(nextLanes)) {
      case DiscreteEventPriority:
        schedulerPriorityLevel = ImmediateSchedulerPriority;
        break;
      case ContinuousEventPriority:
        schedulerPriorityLevel = UserBlockingSchedulerPriority;
        break;
      case DefaultEventPriority:
        schedulerPriorityLevel = NormalSchedulerPriority;
        break;
      case IdleEventPriority:
        schedulerPriorityLevel = IdleSchedulerPriority;
        break;
      default:
        schedulerPriorityLevel = NormalSchedulerPriority;
        break;
    }
    // 调用scheduleCallback传入判断好的scheduler优先级执行
    newCallbackNode = scheduleCallback(
      schedulerPriorityLevel,
      // concurrent模式下调用
      performConcurrentWorkOnRoot.bind(null, root),
    );
  }

  // 赋值之前获取到的lane最高优先级
  root.callbackPriority = newCallbackPriority;
  // 赋值newCallbackNode
  root.callbackNode = newCallbackNode;
}

getHighestPriorityLane

就是那lane进行位运算求出最高优先级lane

export function getHighestPriorityLane(lanes: Lanes): Lane {
  return lanes & -lanes;
}

现在我们假设执行完了ensureRootIsScheduled,然后退出,回到scheduleUpdateOnFiber

scheduleUpdateOnFiber(完)

    .....
        // 如果执行上下文为空, 会取消 schedule 调度
        if (
          lane === SyncLane &&
          executionContext === NoContext &&
          (fiber.mode & ConcurrentMode) === NoMode &&
          // Treat `act` as if it's inside `batchedUpdates`, even in legacy mode.
          !(__DEV__ && ReactCurrentActQueue.isBatchingLegacy)
        ) {
          // Flush the synchronous work now, unless we're already working or inside
          // a batch. This is intentionally inside scheduleUpdateOnFiber instead of
          // scheduleCallbackForFiber to preserve the ability to schedule a callback
          // without immediately flushing it. We only do this for user-initiated
          // updates, to preserve historical behavior of legacy mode.
          resetRenderTimer();
          flushSyncCallbacksOnlyInLegacyMode();
        }
      }
    }

总结

至此初始化阶段就执行完毕了,当执行到ensureRootIsScheduled时就是进入render阶段的最后操作,内部都会调用performSyncWorkOnRoot()/performConcurrentWorkOnRoot(),对于调用哪个WorkOnRoot函数取决于是sync模式还是concurrent模式

记录学习过程,如有错误欢迎指出