任务调度入口函数
文章目录
本文主要过一遍任务调度的几个入口函数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任务。