【React】版本18 代码遨游(十一)任务调度入口函数

任务调度入口函数

本文主要过一遍任务调度的几个入口函数performWork(同步、并行)、renderRoot(同步、并行)、performUnitOfWork、completeUnitOfWork、等方法

位置:packages\react-reconciler\src\ReactFiberWorkLoop.new.js

performSyncWorkOnRoot(root)

// 同步任务不会通过调度器实行
// 此方法为同步任务的入口
function performSyncWorkOnRoot(root) {
  // 如果打开了性能分析,则记录行为
  if (enableProfilerTimer && enableProfilerNestedUpdatePhase) {
    syncNestedUpdateFlag();
  }

  // 确保当前的context不是render、commit环境
  invariant(
    (executionContext & (RenderContext | CommitContext)) === NoContext,
    'Should not already be working.',
  );

  // 执行所有effect tag任务
  flushPassiveEffects();

  // 取得下一批车道
  let lanes = getNextLanes(root, NoLanes);
  // 如果已经没有同步车道
  if (!includesSomeLane(lanes, SyncLane)) {
    // 确保fiberRoot被调度
    ensureRootIsScheduled(root, now());
    return null;
  }

  // 进行渲染根节点的操作,保存返回的退出状态
  let exitStatus = renderRootSync(root, lanes);
  if (root.tag !== LegacyRoot && exitStatus === RootErrored) {
    const prevExecutionContext = executionContext;
    executionContext |= RetryAfterError;

    // 如果注水过程中出错
    // 抛弃服务端的应答,返回客户端渲染
    if (root.hydrate) {
      root.hydrate = false;
      if (__DEV__) {
        errorHydratingContainer(root.containerInfo);
      }
      clearContainer(root.containerInfo);
    }

    // 如果抛错,重新尝试一遍渲染
    // 同步渲染以阻止并行修改,
    // 并且所有挂起的更新都会包括在这次渲染中
    // 如果第二次再次失败,则提交错误
    const errorRetryLanes = getLanesToRetrySynchronouslyOnError(root);
    if (errorRetryLanes !== NoLanes) {
      lanes = errorRetryLanes;
      exitStatus = renderRootSync(root, lanes);
    }

    executionContext = prevExecutionContext;
  }

  // 仍然出错
  if (exitStatus === RootFatalErrored) {
    const fatalError = workInProgressRootFatalError;
    prepareFreshStack(root, NoLanes);
    markRootSuspended(root, lanes);
    // 抛错前确保调度fiberRoot
    ensureRootIsScheduled(root, now());
    throw fatalError;
  }

  // 现在我们有了一致的树(alternate) ,由于是同步渲染,我们无论如何都要提交当前fiberRoot
  const finishedWork: Fiber = (root.current.alternate: any);
  root.finishedWork = finishedWork;
  root.finishedLanes = lanes;
  commitRoot(root);

  // 在退出前,确保调度了fiberRoot
  ensureRootIsScheduled(root, now());

  return null;
}

performConcurrentWorkOnRoot(root, didTimeout)

function performConcurrentWorkOnRoot(root, didTimeout) {
  if (enableProfilerTimer && enableProfilerNestedUpdatePhase) {
    resetNestedUpdateFlag();
  }

  // 当前是React事件,重置记录事件的时间
  currentEventTime = NoTimestamp;
  currentEventTransitionLane = NoLanes;

  invariant(
    (executionContext & (RenderContext | CommitContext)) === NoContext,
    'Should not already be working.',
  );

  // 处理effect tag的方式和同步一致
  const originalCallbackNode = root.callbackNode;
  const didFlushPassiveEffects = flushPassiveEffects();
  if (didFlushPassiveEffects) {
    if (root.callbackNode !== originalCallbackNode) {
      return null;
    } else {
    }
  }

  // 获取车道
  let lanes = getNextLanes(
    root,
    root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes,
  );
  if (lanes === NoLanes) {
    // Defensive coding. This is never expected to happen.
    return null;
  }

  // 如果CPU时间bound触发,或者我们在同步更新模式中,则禁止时间切片,并使用同步渲染
  let exitStatus =
    shouldTimeSlice(root, lanes) &&
    (disableSchedulerTimeoutInWorkLoop || !didTimeout)
      ? renderRootConcurrent(root, lanes)
      : renderRootSync(root, lanes);
  if (exitStatus !== RootIncomplete) {
    if (exitStatus === RootErrored) {
      const prevExecutionContext = executionContext;
      executionContext |= RetryAfterError;

      // 错误处理和同步一致
      if (root.hydrate) {
        root.hydrate = false;
        if (__DEV__) {
          errorHydratingContainer(root.containerInfo);
        }
        clearContainer(root.containerInfo);
      }
      const errorRetryLanes = getLanesToRetrySynchronouslyOnError(root);
      if (errorRetryLanes !== NoLanes) {
        lanes = errorRetryLanes;
        exitStatus = renderRootSync(root, errorRetryLanes);
      }

      executionContext = prevExecutionContext;
    }

    if (exitStatus === RootFatalErrored) {
      const fatalError = workInProgressRootFatalError;
      prepareFreshStack(root, NoLanes);
      markRootSuspended(root, lanes);
      ensureRootIsScheduled(root, now());
      throw fatalError;
    }
    const finishedWork: Fiber = (root.current.alternate: any);
    root.finishedWork = finishedWork;
    root.finishedLanes = lanes;
    finishConcurrentRender(root, exitStatus, lanes);
  }

  ensureRootIsScheduled(root, now());
  if (root.callbackNode === originalCallbackNode) {
    // The task node scheduled for this root is the same one that's
    // currently executed. Need to return a continuation.
    return performConcurrentWorkOnRoot.bind(null, root);
  }
  return null;
}

flushSyncCallbacks()

此方法为 performSyncWorkOnRoot 中确保处理所有effect的核心逻辑:

function flushSyncCallbacks() {
  if (!isFlushingSyncQueue && syncQueue !== null) {
    // 通过flag防止重入逻辑
    isFlushingSyncQueue = true;// 工作索引
    let i = 0;
    // 取得当前优先度
    const previousUpdatePriority = getCurrentUpdatePriority();
    try {
      // 确保同步状态
      const isSync = true;
      // 获取当前的同步队列
      const queue = syncQueue;
      setCurrentUpdatePriority(DiscreteEventPriority);
      // 遍历队列,执行队列任务的回调函数
      for (; i < queue.length; i++) {
        let callback = queue[i];
        do {
          callback = callback(isSync);
        } while (callback !== null);
      }
      syncQueue = null;
      includesLegacySyncCallbacks = false;
    } catch (error) {
      // 如果抛错,将剩余内容保存
      if (syncQueue !== null) {
        syncQueue = syncQueue.slice(i + 1);
      }
      // 在下一次调度中继续flush
      scheduleCallback(ImmediatePriority, flushSyncCallbacks);
      throw error;
    } finally {
      setCurrentUpdatePriority(previousUpdatePriority);
      // 恢复flag
      isFlushingSyncQueue = false;
    }
  }
  return null;
}

performUnitOfWork(unitOfWork: Fiber)

本方法通过beginWork处理节点操作,并且创建(可能的)子节点next,若其非空,则循环对其进行节点操作,直到所有子节点都处理完,退出workLoop

function performUnitOfWork(unitOfWork: Fiber): void {
  const current = unitOfWork.alternate;
  setCurrentDebugFiberInDEV(unitOfWork);

  // 储存可能的子节点
  let next;
  if (enableProfilerTimer && (unitOfWork.mode & ProfileMode) !== NoMode) {
    // 性能分析用
    startProfilerTimer(unitOfWork);
    next = beginWork(current, unitOfWork, subtreeRenderLanes);
    stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true);
  } else {
    // 进入beginWork处理节点
    next = beginWork(current, unitOfWork, subtreeRenderLanes);
  }

  resetCurrentDebugFiberInDEV();
  unitOfWork.memoizedProps = unitOfWork.pendingProps;
  if (next === null) {
    // 没有新的子节点产生,本轮performUnitOfWork完成
    completeUnitOfWork(unitOfWork);
  } else {
    // 继续处理新产生的子节点
    workInProgress = next;
  }

  ReactCurrentOwner.current = null;
}

completeUnitOfWork(unitOfWork: Fiber)

function completeUnitOfWork(unitOfWork: Fiber): void {
  // 完成当前单元工作,并移动到下一个兄弟节点,如果没有兄弟节点则返回至父fiber
  let completedWork = unitOfWork;
  do {
    // 获取当前节点以及返回fiber
    const current = completedWork.alternate;
    const returnFiber = completedWork.return;

    // 检查工作是否完成、有无抛错
    if ((completedWork.flags & Incomplete) === NoFlags) {
      setCurrentDebugFiberInDEV(completedWork);
      let next;
      if (
        !enableProfilerTimer ||
        (completedWork.mode & ProfileMode) === NoMode
      ) {
        // 完成阶段,处理当前节点的effect tag,并且保存返回节点,直到root
        next = completeWork(current, completedWork, subtreeRenderLanes);
      } else {
        startProfilerTimer(completedWork);
        next = completeWork(current, completedWork, subtreeRenderLanes);
        stopProfilerTimerIfRunningAndRecordDelta(completedWork, false);
      }
      resetCurrentDebugFiberInDEV();

      if (next !== null) {
        // 完成新出现的节点effect tag
        workInProgress = next;
        return;
      }
    } else {
      // 如果抛出异常,则此节点无法完成
      // 保存未处理的内容
      const next = unwindWork(completedWork, subtreeRenderLanes);

      // fiber未完成,无需重置lanes

      if (next !== null) {
        // 首先处理新生成的
        // 将除了host effect tag之外的全部清除
        next.flags &= HostEffectMask;
        workInProgress = next;
        return;
      }

      if (
        enableProfilerTimer &&
        (completedWork.mode & ProfileMode) !== NoMode
      ) {
        stopProfilerTimerIfRunningAndRecordDelta(completedWork, false);

        // 记录发生错误的处理所花时间
        let actualDuration = completedWork.actualDuration;
        let child = completedWork.child;
        while (child !== null) {
          actualDuration += child.actualDuration;
          child = child.sibling;
        }
        completedWork.actualDuration = actualDuration;
      }

      if (returnFiber !== null) {
        // 标记父fiber未完成,将当前子树的标记清空
        returnFiber.flags |= Incomplete;
        returnFiber.subtreeFlags = NoFlags;
        returnFiber.deletions = null;
      }
    }

    const siblingFiber = completedWork.sibling;
    if (siblingFiber !== null) {
      // 处理兄弟fiber
      workInProgress = siblingFiber;
      return;
    }
    // 若已没有兄弟fiber,返回父fiber
    completedWork = returnFiber;
    // 保存当前已完成的工作
    workInProgress = completedWork;
  } while (completedWork !== null);

  // 处理到根节点
  if (workInProgressRootExitStatus === RootIncomplete) {
    workInProgressRootExitStatus = RootCompleted;
  }
}

renderRootSync(root: FiberRoot, lanes: Lanes)

function renderRootSync(root: FiberRoot, lanes: Lanes) {
  // 储存上一个执行context
  const prevExecutionContext = executionContext;
  // 切换至renderContext
  executionContext |= RenderContext;
  const prevDispatcher = pushDispatcher();

  // 如果fiberRoot或者车道改变了,将当前堆栈抛出,并准备一个新的
  if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {
    if (enableUpdaterTracking) {
      if (isDevToolsPresent) {
        const memoizedUpdaters = root.memoizedUpdaters;
        if (memoizedUpdaters.size > 0) {
          restorePendingUpdaters(root, workInProgressRootRenderLanes);
          memoizedUpdaters.clear();
        }

        // 将之前的堆栈移动到保存点,如果当前work失效,则回到保存的堆栈信息中
        // 此步骤必须在当前work生成更多新的同优先度的work之前完成,以区分不同update
        movePendingFibersToMemoized(root, lanes);
      }
    }

    // 准备全新的堆栈
    prepareFreshStack(root, lanes);
  }

  if (__DEV__) {
    if (enableDebugTracing) {
      logRenderStarted(lanes);
    }
  }

  if (enableSchedulingProfiler) {
    markRenderStarted(lanes);
  }

  do {
    try {
      // 进入workLoop循环
      workLoopSync();
      break;
    } catch (thrownValue) {
      handleError(root, thrownValue);
    }
  } while (true);
  resetContextDependencies();

  executionContext = prevExecutionContext;
  popDispatcher(prevDispatcher);

  if (workInProgress !== null) {
    // 同步渲染应该完成了所有work,因此进入此分支即未知bug
    invariant(
      false,
      'Cannot commit an incomplete root. This error is likely caused by a ' +
        'bug in React. Please file an issue.',
    );
  }

  if (__DEV__) {
    if (enableDebugTracing) {
      logRenderStopped();
    }
  }

  if (enableSchedulingProfiler) {
    markRenderStopped();
  }

  // 设置当前没有进行中的根渲染及车道
  workInProgressRoot = null;
  workInProgressRootRenderLanes = NoLanes;

  return workInProgressRootExitStatus;
}

workLoopSync()

function workLoopSync() {
  // 循环处理performUnitOfWork直到没有更多的work需要处理
  while (workInProgress !== null) {
    performUnitOfWork(workInProgress);
  }
}

workLoopConcurrent()

function workLoopConcurrent() {
  // 调度器可以随时告知我们中断循环并yield
  while (workInProgress !== null && !shouldYield()) {
    performUnitOfWork(workInProgress);
  }
}

总结

至此,我们从入口处,略微初探了渲染fiberRoot的开始阶段。

  • 我们从入口函数perform(Sync/Concurrent)WorkOnRoot进入渲染根节点流程
  • flush所有Effect Tag的任务
  • 进入renderRoot(Sync/Concurrent)方法函数
  • 进入workLoop(Sync/Concurrent)循环处理方法
  • 在每一次work处理中,使用performUnitOfWork处理每一单元的work,在每一单元的处理中,每一次处理单个work任务,都进入beginWork方法,此方法可能会产生新的任务,直到当前节点的所有衍生任务都完成之后,我们进入completeUnitOfWork试图完成此单元的Work
  • 在completeUnitOfWork中,我们检查当前单元的兄弟节点,并设置下一轮的单元为下一个兄弟节点。直到当前节点所有兄弟节点都已完成,则处理当前节点的父节点。如此循环,直到我们返回到根节点。
  • 至此,根上所有节点都渲染处理完成。

在下一节,我们会查看beginWork方法,看处理work过程中,会做哪些工作,并且如何产生新的work任务。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值