React18.2源码解析之初始化阶段(下)
记录学习过程,如有错误欢迎指出
上一篇文章我们讲到了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模式
记录学习过程,如有错误欢迎指出
转载自:https://juejin.cn/post/7139528956834742308