react回调函数_react源码个人笔记-版本17.0.0(笔记03)
初始化过程 //unbatchedUpdates 方法定义(1)// 执行非批量更新的操作// 代码位置: src/react/packages/react-reconciler/src/ReactFiberWorkLoop.old.js// 主题逻辑: 保存初始上下文,增加非批量上下文,删除批量更新上下文, 执行函数, 重置上下文,重置时间和执行同步队列export function ...
初始化过程
// unbatchedUpdates 方法定义(1)
// 执行非批量更新的操作
// 代码位置: src/react/packages/react-reconciler/src/ReactFiberWorkLoop.old.js
// 主题逻辑: 保存初始上下文,增加非批量上下文,删除批量更新上下文, 执行函数, 重置上下文,重置时间和执行同步队列
export function unbatchedUpdates<A, R>(fn: (a: A) => R, a: A): R {
// 原来的执行上下文
// BatchedContext = 0b000001
// LegacyUnbatchedContext = 0b001000
// executionContext = 0b001000 = 8
// 0b000000 & 0b111110
const prevExecutionContext = executionContext; // 获取当前上下文 // 0b000000 & 0b111110
executionContext &= ~BatchedContext; // 去除批量更新的标记 1
executionContext |= LegacyUnbatchedContext; // 增加非批量执行上下文 8
// 0b000000 | 0b001000
try {
return fn(a); // 执行函数
} finally {
executionContext = prevExecutionContext; // 保存原来的执行参数
if (executionContext === NoContext) { // 无上下文时
// Flush the immediate callbacks that were scheduled during this batch
resetRenderTimer(); // 重置渲染时间
// 首次执行不会进入flushSyncCallbackQueue先不展开
// 刷新次批调度任务中的立即回调函数
// 首次执行不会进入flushSyncCallbackQueue先不展开
// 刷新次批调度任务中的立即清空函数
flushSyncCallbackQueue(); //
}
}
}
备注: unbatchedUpdates 存储当前上下文,去除批量上下文,增加非批量更新上下文,执行函数fn, 结束后,还原上下文,当无上下文,重置渲染时间和清空同步回调函数。
// 定义resetRenderTimer 函数(2)
// 重置渲染时间
// 代码位置: src/react/packages/react-reconciler/src/ReactFiberWorkLoop.old.js
// 主题逻辑: 重置workInProgressRootRenderTargetTime 时间为当前时间 + 500
function resetRenderTimer() {
// fiber的触发时间
// 当前时间再加500
workInProgressRootRenderTargetTime = now() + RENDER_TIMEOUT_MS;
}
const RENDER_TIMEOUT_MS = 500;
备注: 将workInProgressRootRenderTargetTime ?下一个渲染时间设置为当前时间+ 500
// 定义flushSyncCallbackQueue 函数(3)
// 执行flush, 执行同步回调队列
// 代码位置: src/react/packages/react-reconciler/src/SchedulerWithReactIntegration.old.js
// 主体逻辑: 清空回调队列
export function flushSyncCallbackQueue() {
// immediateQueueCallbackNode 还存在数据
if (immediateQueueCallbackNode !== null) {
const node = immediateQueueCallbackNode;
immediateQueueCallbackNode = null;
Scheduler_cancelCallback(node); //设置callback 为null
}
// 清空同步任务队列, 后续补充
flushSyncCallbackQueueImpl();
}
// 定义updateContainer 函数并(4)
// 进行调度
// 代码位置: src/react/packages/react-reconciler/src/ReactFiberReconciler.old.js
// 主体逻辑: 新建lane 和eventTime, 获取context, 开始进行调度
// 进行调度
export function updateContainer(
element: ReactNodeList, // children
container: OpaqueRoot, // fiberRoot 节点
parentComponent: ?React$Component<any, any>, // null
callback: ?Function, // 回调函数
): Lane {
// rootFiber 节点
const current = container.current; // rootFiber 节点
// 获取eventTime 时间 // deferRenderPhaseUpdateToNextBatch
const eventTime = requestEventTime();
// 获取lane
const lane = requestUpdateLane(current); // 1
// 可以忽略
if (enableSchedulingProfiler) {
markRenderScheduled(lane);
}
// parentComponent : null
// 获取当前节点和子节点的上下文
const context = getContextForSubtree(parentComponent);// {}
if (container.context === null) {
container.context = context;
// fiberRoot.context = {}
} else {
container.pendingContext = context;
}
// 创建更新 // 创建一个更新对线
const update = createUpdate(eventTime, lane);
// Caution: React DevTools currently depends on this property
// being called "element".
update.payload = {element}; // 更新的payload
// 回调函数
callback = callback === undefined ? null : callback;
if (callback !== null) {
// 设置回调函数
update.callback = callback;
}
// 插入更新
enqueueUpdate(current, update);
// 进行调度
// 当前的fiber, lane shijian
// 没有在 非(commit render) 或在 commit , 才需要进行调度
scheduleUpdateOnFiber(current, lane, eventTime);
// render 可以做初次渲染,和再次更新
return lane;
}
// requestEventTime 函数定义(5)
// 获取请求时间
// executionContext = 0b001000
// RenderContext = 0b010000;
// CommitContext = 0b100000;
// 代码位置: src/react/packages/react-reconciler/src/ReactFiberWorkLoop.old.js
// 主体逻辑: 1,为render, commit阶段,获取当前时间, 2 .其他阶段时间为,统一的时间,批量更新
// 3 初始化阶段, 初次获取的时候,获取当前时间
export function requestEventTime() {
// 执行的上下文是render或者commit,在执行阶段获取真实时间, 当正在 处于render 或者commit 阶段的时候, 就是当前水岸i
// 情况 1
if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {
// We're inside React, so it's fine to read the actual time.
// 就取现在时间 // 我们在React内部,因此可以读取实际时间
return now();
}
// We're not inside React, so we may be in the middle of a browser event.
// 非commit 或render 时间啊, 当不为空。 取当前event 时间
// 如果我们没在react内部更新中,可能是在执行浏览器的任务中
// 我们不在React内部,因此我们可能处于浏览器事件的中间。
// 情况2
if (currentEventTime !== NoTimestamp) {
// Use the same start time for all updates until we enter React again.
// 对所有更新使用相同的开始时间,直到我们再次进入React
return currentEventTime;
}
// This is the first update since React yielded. Compute a new start time.
// 第一次更新的时候
// 之前的任务已经执行完,开启新的任务时候需要重新计算时间
// 情况3
currentEventTime = now();
// 这是自React产生以来的第一次更新。计算新的开始时间。
// 返回
// 3
return currentEventTime;
}
// src/react/packages/react-reconciler/src/SchedulerWithReactIntegration.old.js
// 初始的时间
const initialTimeMs: number = Scheduler_now();
const {
unstable_now: Scheduler_now, // 定义Schedule_now 的实现
} = Scheduler;
export const now =
initialTimeMs < 10000 ? Scheduler_now : () => Scheduler_now() - initialTimeMs;
// src/react/packages/scheduler/src/forks/SchedulerHostConfig.default.js
// getCurrentTime = getCurrentTime;
// src/react/packages/scheduler/src/Scheduler.js
export {
getCurrentTime as unstable_now, // 获取当前时间
}
const localPerformance = performance;
getCurrentTime = () => localPerformance.now();
备注信息: requestEventTime, (1)当一次调用时, 通过now()获取当前时间,返回,符合情况3;(2) 情况1 当处于render 或commit 阶段时, 总是返回now()的时间;(3) 情况2时, 即当前处于非render 且非commit阶段时,总是返回已经储存的currentEventTime, 即在这个时间段的返回相同的时间,时间相同,为了进行批量更新。
// requestUpdateLane 函数定义 (6)
// 获取请求更新的Lane
// 代码位置 src/react/packages/react-reconciler/src/ReactFiberWorkLoop.old.js
// 主体逻辑: 当普通初始化,为同步,其次
// 情况1 非BlockingMode 模式, 同步
// 情况2 非BlockingMode 且非ConcurrentMode模式, 通过getCurrentPriorityLevel 判断,
// 是同步还是批量同步
// 情况3
export function requestUpdateLane(fiber: Fiber): Lane {
// Special cases
// fiber de mode格式
const mode = fiber.mode; // 0
// 旧模式中lane只为SyncLane = 1
// 当与 BlockingMode BlockingMode = 0b00010;
// 当为 非BlockingMode 模式, 就是同步
if ((mode & BlockingMode) === NoMode) { // const NoMode = 0b00000;
// 同步的 旧模式中lane只为SyncLane = 1
return (SyncLane: Lane); // 1
} else if ((mode & ConcurrentMode) === NoMode) { //非ConcurrentMode的模式
// 模式为非 ConcurrentMode 模式
return getCurrentPriorityLevel() === ImmediateSchedulerPriority
? (SyncLane: Lane) // 同步
: (SyncBatchedLane: Lane); // 同步批量
} else if (
!deferRenderPhaseUpdateToNextBatch &&
(executionContext & RenderContext) !== NoContext &&
workInProgressRootRenderLanes !== NoLanes
) {
// 渲染阶段
return pickArbitraryLane(workInProgressRootRenderLanes);
}
// We'll do the same for `currentEventPendingLanes` below.
if (currentEventWipLanes === NoLanes) {
currentEventWipLanes = workInProgressRootIncludedLanes;
}
const isTransition = requestCurrentTransition() !== NoTransition;
if (isTransition) {
if (currentEventPendingLanes !== NoLanes) {
currentEventPendingLanes =
mostRecentlyUpdatedRoot !== null
? mostRecentlyUpdatedRoot.pendingLanes
: NoLanes;
}
return findTransitionLane(currentEventWipLanes, currentEventPendingLanes);
}
// TODO: Remove this dependency on the Scheduler priority.
// To do that, we're replacing it with an update lane priority.
const schedulerPriority = getCurrentPriorityLevel();
let lane;
if (
// TODO: Temporary. We're removing the concept of discrete updates.
(executionContext & DiscreteEventContext) !== NoContext &&
schedulerPriority === UserBlockingSchedulerPriority
) {
lane = findUpdateLane(InputDiscreteLanePriority, currentEventWipLanes);
} else {
const schedulerLanePriority = schedulerPriorityToLanePriority(
schedulerPriority,
);
if (decoupleUpdatePriorityFromScheduler) {
const currentUpdateLanePriority = getCurrentUpdateLanePriority();
if (
schedulerLanePriority !== currentUpdateLanePriority &&
currentUpdateLanePriority !== NoLanePriority
) {
if (__DEV__) {
console.error(
'Expected current scheduler lane priority %s to match current update lane priority %s',
schedulerLanePriority,
currentUpdateLanePriority,
);
}
}
}
lane = findUpdateLane(schedulerLanePriority, currentEventWipLanes);
}
return lane;
}
// getContextForSubtree 函数定义(7)
// 获取上下文
// 代码位置: src/react/packages/react-reconciler/src/ReactFiberReconciler.old.js
// 主体逻辑: 获取上下文
function getContextForSubtree(
parentComponent: ?React$Component<any, any>,
): Object {
// 空对象, 为上下文, 根组件的context 为null
if (!parentComponent) {
return emptyContextObject; // {}
}
// 获取
const fiber = getInstance(parentComponent);
// context api
const parentContext = findCurrentUnmaskedContext(fiber);
// 值
if (fiber.tag === ClassComponent) {
const Component = fiber.type;
if (isLegacyContextProvider(Component)) {
return processChildContext(fiber, Component, parentContext);
}
}
return parentContext;
}
// 备注 export const emptyContextObject = {};
// import {get as getInstance} from 'shared/ReactInstanceMap';
// 获取对应的fiber
export function get(key) {
return key._reactInternals;
}
// 判断是否为新的context Provider 提供者
function isContextProvider(type: Function): boolean {
// 即将废弃的context是否不可使用
if (disableLegacyContext) { //disableLegacyContext : false
// false
return false;
} else {
// true 旧的context
const childContextTypes = type.childContextTypes;
return childContextTypes !== null && childContextTypes !== undefined;
}
}
// 禁止遗留的context : false
export const disableLegacyContext = false;
// 获取当前 context
// 获取 当前所处的context
function findCurrentUnmaskedContext(fiber: Fiber): Object {
if (disableLegacyContext) { // false
return emptyContextObject; // {}
} else {
let node = fiber;
do {
switch (node.tag) {
case HostRoot: // 根节点
return node.stateNode.context;
case ClassComponent: { // 最近的classComponent
const Component = node.type;
if (isContextProvider(Component)) {
return node.stateNode.__reactInternalMemoizedMergedChildContext;
}
break;
}
}
node = node.return; // 往上遍历
} while (node !== null);
}
}
// 处理context 的合并
// src/react/packages/react-reconciler/src/ReactFiberContext.old.js
// 自己所处的context 与提供的context 合并
function processChildContext(
fiber: Fiber,
type: any,
parentContext: Object,
): Object {
if (disableLegacyContext) {
return parentContext;
} else {
const instance = fiber.stateNode;
const childContextTypes = type.childContextTypes;
// TODO (bvaughn) Replace this behavior with an invariant() in the future.
// It has only been added in Fiber to match the (unintentional) behavior in Stack.
if (typeof instance.getChildContext !== 'function') {
return parentContext;
}
const childContext = instance.getChildContext();
for (const contextKey in childContext) {
invariant(
contextKey in childContextTypes,
'%s.getChildContext(): key "%s" is not defined in childContextTypes.',
getComponentName(type) || 'Unknown',
contextKey,
);
}
// 最近的可以覆盖更高的
return {...parentContext, ...childContext};
}
}
// createUpdate 定义(8)
// 创建更新
// 代码位置: src/react/packages/react-reconciler/src/ReactUpdateQueue.old.js
// 主体逻辑: 创建更新
export function createUpdate(eventTime: number, lane: Lane): Update<*> {
const update: Update<*> = {
eventTime, // 事件事件
lane, // lane
// export const UpdateState = 0;
// export const ReplaceState = 1;
// export const ForceUpdate = 2;
// export const CaptureUpdate = 3; // 渲染出现问题,被捕获后, 渲染新的状态
// 指定更新的类型,值为以上几种
tag: UpdateState, // 普通的更新, 更新类型
// 更新内容,比如`setState`接收的第一个参数
payload: null,
// 对应的回调,`setState`,`render`都有
callback: null,
// 指向下一个更新
next: null,
};
return update;
}
// enqueueUpdate 函数, 插入更新 (9)
// 插入更新,将update 插入
// 代码位置: src/react/packages/react-reconciler/src/ReactUpdateQueue.old.js
// 主体逻辑: 在rootFiber updateQueue 增加update
export function enqueueUpdate<State>(fiber: Fiber, update: Update<State>) {
// 当前更新的updateQueue
const updateQueue = fiber.updateQueue;
// fiber 没有被挂载
if (updateQueue === null) {
// Only occurs if the fiber has been unmounted.
return;
}
// 共享的queue
const sharedQueue: SharedQueue<State> = (updateQueue: any).shared;
// 等待的, 初始化为
const pending = sharedQueue.pending;
// 为空
if (pending === null) {
// This is the first update. Create a circular list.
// 这是第一次更新,创建一个循环单链表
update.next = update;
// 最终结构为sharedQueue.pending = update
// update.next = update 循环指向自己
// 只有一个 update1
// sharedQueue.pending = update1
// update1.next = update1
} else {
// 优先级更高, 插入到pending 之后
update.next = pending.next; //
pending.next = update; // 将update 插入在pending 与pending.next 中间
// pending --next--> update --next--> pending.next 中间
// 双重指向, 指向自己
// update -next-> pending.next
// sharedQueue.pending = update;
// update1 update2 2个
// sharedQueue.pending = update2; update2.next = update1; update1.next= update2
// update1 update2 update3 3个
// sharedQueue.pending = update3; update3.next = update1; update1.next= update2; update2.next= update3;
// ......
}
// 等待更新的
sharedQueue.pending = update; // 链式结构, 赋值
}
// scheduleUpdateOnFiber 函数定义 (10)
// 执行调度工作在fiber , 调度模块
// 位置: src/react/packages/react-reconciler/src/ReactFiberWorkLoop.old.js
// 逻辑: 1 更新触发点fiber的lanes, 对应所有父节点fiber 的childLanes, 2 ,在fiberRoot
// 上增加lans 和eventTime, 3 当在render时,直接合并 4 逻辑分支, 当更新为同步,非同步更新,
// 且非render,commie 阶段,直接performSyncWorkOnRoot ,同步,其他情况, flushSyncCallbackQueue
// 异步更新时 ensureRootIsScheduled
// 执行调度工作在fiber , 调度模块
export function scheduleUpdateOnFiber(
fiber: Fiber, // 触发fiber
lane: Lane, // 更新的lane
eventTime: number, //触发更新的时间
) {
// update 中数量控制
// 检查最大update的数量是否超过了最大值
checkForNestedUpdates();
// 实现警告, render 中调用setState
warnAboutRenderPhaseUpdatesInDEV(fiber); // 不能在render 阶段设置setState
// 找寻fiberRoot, 并表示所有父fiber de childLanes
// 1 标示source fiber 的lanes sourrce 的alter的alne
// 2 标示source fiber 所有父节点的 childLanes 对应 alternate 的childLanes
// 3 返回fiberROot
const root = markUpdateLaneFromFiberToRoot(fiber, lane);
// root 不存在时, 开发报错 fiberRoot
if (root === null) {
warnAboutUpdateOnUnmountedFiberInDEV(fiber);
return null;
}
// Mark that the root has a pending update.
// 标示现在root 具有一个d等待的更新
markRootUpdated(root, lane, eventTime);
// 如果当前是workInProget
// 已经在进行调度
if (root === workInProgressRoot) { // 存在数据的时候
// deferRenderPhaseUpdateToNextBatch 当前环境为 true
if (
deferRenderPhaseUpdateToNextBatch ||
(executionContext & RenderContext) === NoContext
) {
// 在commit 的阶段吗?
// 在render 阶段, 或者 deferRenderPhaseUpdateToNextBatch
// 当前的环境
// 没有在 非(commit render) 或在 commit , 才需要进行调度? 16.6
// 对lanes 进行合并
workInProgressRootUpdatedLanes = mergeLanes(
workInProgressRootUpdatedLanes,
lane,
);
// 优先级合并
}
// 推测时suspend
if (workInProgressRootExitStatus === RootSuspendedWithDelay) {
markRootSuspended(root, workInProgressRootRenderLanes);
}
}
// TODO: requestUpdateLanePriority also reads the priority. Pass the
// priority as an argument to that function and this one.
// 获取当前环境的优先级
const priorityLevel = getCurrentPriorityLevel(); // 97
// executionContext 执行环境 同步更新时
// 同步更新的时候
if (lane === SyncLane) { //
// 非批量更新 ,且 未进行render 或commit
if (
// Check if we're inside unbatchedUpdates
(executionContext & LegacyUnbatchedContext) !== NoContext &&
// Check if we're not already rendering
(executionContext & (RenderContext | CommitContext)) === NoContext
) {
// 非同步更新, 且在非render commit 阶段
// 处于非LegacyUnbatchedContext 批量, 且不处于render和commit
// Register pending interactions on the root to avoid losing traced interaction data.
// 注册 等待的相互作用在root , 避免丢失数据
// 不执行
schedulePendingInteractions(root, lane);
// 执行同步的更新
performSyncWorkOnRoot(root);
} else {
// 其他情况
ensureRootIsScheduled(root, eventTime);
// 不执行
schedulePendingInteractions(root, lane);
// 没有上下文的情况
if (executionContext === NoContext) {
// 马上清空同步任务,除非我们已经进入batch。
// 故意将其放在scheduleUpdateOnFiber而不是scheduleCallbackForFiber中,以保留安排回调的功能无需立即清空。
// 我们仅针对用户发起的操作更新,以保留旧版模式的历史行为。
resetRenderTimer();
// 同步的更新
flushSyncCallbackQueue();
}
}
} else {
// 异步的更新的时候
// Schedule a discrete update but only if it's not Sync.
// 当更新为离散的更新,且非同步
if (
(executionContext & DiscreteEventContext) !== NoContext && // 执行上下文为离散事件
// Only updates at user-blocking priority or greater are considered
// discrete, even inside a discrete event.
// 优先级为UserBlockingSchedulerPriority 或ImmediateSchedulerPriority
(priorityLevel === UserBlockingSchedulerPriority ||
priorityLevel === ImmediateSchedulerPriority)
) {
// This is the result of a discrete event. Track the lowest priority
// discrete update per root so we can flush them early, if needed.
if (rootsWithPendingDiscreteUpdates === null) {
rootsWithPendingDiscreteUpdates = new Set([root]);
// 在rootsWithPendingDiscreteUpdates 添加root , 暂不理解
} else {
rootsWithPendingDiscreteUpdates.add(root);
}
}
// Schedule other updates after in case the callback is sync.
ensureRootIsScheduled(root, eventTime);
schedulePendingInteractions(root, lane);
}
// We use this when assigning a lane for a transition inside
// `requestUpdateLane`. We assume it's the same as the root being updated,
// since in the common case of a single root app it probably is. If it's not
// the same root, then it's not a huge deal, we just might batch more stuff
// together more than necessary.
// 设置最近更新的root
mostRecentlyUpdatedRoot = root;
// 16.6 执行的事情
// 1 加入root调度队列, 判断当前是否为批量更新
// 3 根据expirationTime判断调度类型
}
// getCurrentPriorityLevel 函数定义(11)
// 位置: src/react/packages/react-reconciler/src/SchedulerWithReactIntegration.old.js
// 逻辑 通过Scheduler_getCurrentPriorityLevel 获取当前的优先级
export function getCurrentPriorityLevel(): ReactPriorityLevel {
switch (Scheduler_getCurrentPriorityLevel()) {
// 调度, 立即执行优先级
case Scheduler_ImmediatePriority:
return ImmediatePriority; // 99
// 调度 用户阻塞
case Scheduler_UserBlockingPriority:
return UserBlockingPriority; // 98
// 调度, 普通优先级
case Scheduler_NormalPriority:
return NormalPriority; // 97
// 调度, 低优先级
case Scheduler_LowPriority:
return LowPriority; // 96
// 调度 idleProperity 优先级
case Scheduler_IdlePriority:
return IdlePriority; // 95
default:
invariant(false, 'Unknown priority level.');
}
}
//备注
const {
unstable_getCurrentPriorityLevel: Scheduler_getCurrentPriorityLevel,
} = Scheduler;
// 获取当前的优先级
// src/react/packages/scheduler/src/Scheduler.js
function unstable_getCurrentPriorityLevel() {
return currentPriorityLevel; // 当前的优先级
}
// markUpdateLaneFromFiberToRoot 函数定义(12)
// 从当前fiber 找寻rootFiber, 并表示
// 位置: src/react/packages/react-reconciler/src/ReactFiberWorkLoop.old.js
// 逻辑: 更新触发fiber的lanes, 如alternate 存在也更新, 往上遍历父fiber, 更新childLans,
//同样对alternate 处理一样, 返回fiberRoot
function markUpdateLaneFromFiberToRoot(
sourceFiber: Fiber, // 触发更新的fiber
lane: Lane, // lame
): FiberRoot | null {
debugger;
// Update the source fiber's lanes
// 更新lanes, 更新当前fiber 的lines
sourceFiber.lanes = mergeLanes(sourceFiber.lanes, lane);
// 就的fiber
let alternate = sourceFiber.alternate;
// 非空
if (alternate !== null) {
alternate.lanes = mergeLanes(alternate.lanes, lane);
}
// Walk the parent path to the root and update the child expiration time.
// 当前的fiber
let node = sourceFiber;
// 父fiber
let parent = sourceFiber.return;
while (parent !== null) {
// 父fiber 的childLanes 合并
parent.childLanes = mergeLanes(parent.childLanes, lane);
alternate = parent.alternate;
// 非空
if (alternate !== null) {
// 就的也更新
alternate.childLanes = mergeLanes(alternate.childLanes, lane);
}
// 递归调用
node = parent;//
parent = parent.return;
}
// 找寻
if (node.tag === HostRoot) {
// fiberRoot
const root: FiberRoot = node.stateNode; // fiberRoot
return root;
} else {
return null;
}
}
// markRootUpdated 定义(13)
// markRootUpdated 定义(13)// 标示当前FiberRoot 的更新
// 位置: src/react/packages/react-reconciler/src/ReactFiberLane.js
// 逻辑:root 中 pendingLanes更新,eventTimes 更新, 其他逻辑
export function markRootUpdated(
root: FiberRoot, // fiberRoot
updateLane: Lane, // 最新的lane
eventTime: number, // 时间
) {
// root上的pendimgLanes 增加
// root.pendingLanes = NoLanes = 0
// updateLane = 1
root.pendingLanes |= updateLane; // 增加一个g更新等级 .// root.pendingLanes : 0,
// updateLane : 1
// Unsuspend any update at equal or lower priority.
// 现在,我们使用与旧的ExpirationTimes模型相同的启发式方法:
// 重试一些lane在相同或者更低的优先级,但不尝试更新那些更高优先级的
// 但不包括更低优先级的更新。这很好
// 在考虑不同优先级的更新时,但不是足以在相同优先级内进行更新
// 我们希望并行的处理这些更新
const higherPriorityLanes = updateLane - 1; // 1-0 : 0
root.suspendedLanes &= higherPriorityLanes; // 0
root.pingedLanes &= higherPriorityLanes; // 0
// 获取所有的eventTimes
const eventTimes = root.eventTimes; // 更新时间数组,31位的数组
// 更新等级
const index = laneToIndex(updateLane); // 对应更新的时间, 更新1 所处的位置: 0
// We can always overwrite an existing timestamp because we prefer the most
// recent event, and we assume time is monotonically increasing.
eventTimes[index] = eventTime; // 更新触发更新的时间 // 第一位设置了时间值
}
// 获取当前的更新的位数, 总共31位数组, 找寻lanes 所处的位置
function pickArbitraryLaneIndex(lanes: Lanes) {
return 31 - clz32(lanes);
}
// 更新等级
function laneToIndex(lane: Lane) {
return pickArbitraryLaneIndex(lane);
}
const clz32 = Math.clz32 ? Math.clz32 : clz32Fallback;
const log = Math.log;
const LN2 = Math.LN2;
function clz32Fallback(lanes: Lanes | Lane) {
if (lanes === 0) {
return 32;
}
return (31 - ((log(lanes) / LN2) | 0)) | 0;
}
// 备注: markRootUpdated 将updateLane更新到pendingLanes, 并将suspendedLanes ,pingedLanes 首先与小于的updateLane(updateLane -1)区并,再进行更行, 并更新updateLane 对应的eventTime
// performSyncWorkOnRoot (14) 初始化非批量同步更新
// 执行非同步更新在root, 处理更新
// src/react/packages/react-reconciler/src/ReactFiberWorkLoop.old.js
// 逻辑, 初始化逻辑: 获取lanes 执行renderRootSync
function performSyncWorkOnRoot(root) {
// 初次渲染不进入
flushPassiveEffects();
let lanes;
let exitStatus;
// 初次渲染不进入, workInProgressRoot 为null
// 已经进入workInProgressRoot有值, 且, 过期
if (root === workInProgressRoot &&includesSomeLane(root.expiredLanes, workInProgressRootRenderLanes)) {
// 这是一颗不完整的树,并且最少其中一条lane已经过期,完成渲染
// 在渲染其余过期工作之前,请完成渲染。
// There's a partial tree, and at least one of its lanes has expired. Finish
// rendering it before rendering the rest of the expired work.
lanes = workInProgressRootRenderLanes; // 1
exitStatus = renderRootSync(root, lanes);
if (includesSomeLane(workInProgressRootIncludedLanes, workInProgressRootUpdatedLanes )) {
// are no interleaved events.
// 渲染包括在渲染阶段更新的lanes。
// 例如,当取消隐藏隐藏的树时,我们包括所有lanes
// 隐藏树时先前已跳过的内容。该lanes是我们开始渲染时使用的lanes的超集。
// 请注意,这仅在部分树被渲染时发生
// 同时。如果整个树是同步呈现的,则没有交错事件。
lanes = getNextLanes(root, lanes); // 获取当前的lanes
// 处理更新
exitStatus = renderRootSync(root, lanes);
}
} else {
// 首次渲染进入这里
lanes = getNextLanes(root, NoLanes); // 当前lanes
exitStatus = renderRootSync(root, lanes); // lanes : 1
}
// root.tag 为有其他模式, 有错误的情况
if (root.tag !== LegacyRoot && exitStatus === RootErrored) {
executionContext |= RetryAfterError; // 上下文添加错误,再次渲染
// If an error occurred during hydration,
// discard server response and fall back to client side render.
// 不研究
if (root.hydrate) {
root.hydrate = false;
clearContainer(root.containerInfo);
}
// If something threw an error, try rendering one more time. We'll render
// synchronously to block concurrent data mutations, and we'll includes
// all pending updates are included. If it still fails after the second
// attempt, we'll give up and commit the resulting tree.
lanes = getLanesToRetrySynchronouslyOnError(root);
// 具有更新吗
if (lanes !== NoLanes) {
exitStatus = renderRootSync(root, lanes);
}
}
// 致命错误
if (exitStatus === RootFatalErrored) {
const fatalError = workInProgressRootFatalError;
prepareFreshStack(root, NoLanes);
markRootSuspended(root, lanes);
ensureRootIsScheduled(root, now());
throw fatalError;
}
// We now have a consistent tree. Because this is a sync render, we
// will commit it even if something suspended.
// 标示完成的工作
const finishedWork: Fiber = (root.current.alternate: any);
root.finishedWork = finishedWork;
root.finishedLanes = lanes;
// 开始commitRoot的部分
commitRoot(root);
// Before exiting, make sure there's a callback scheduled for the next
// pending level.
ensureRootIsScheduled(root, now());
return null;
}
// 是否包含
export function includesSomeLane(a: Lanes | Lane, b: Lanes | Lane) {
return (a & b) !== NoLanes;
}
export const NoContext = /* */ 0b0000000; // 没有上下文
const BatchedContext = /* */ 0b0000001; // 批量更新上下文
const EventContext = /* */ 0b0000010; // 事件上下文
const DiscreteEventContext = /* */ 0b0000100; // 离散事件的上下文
const LegacyUnbatchedContext = /* */ 0b0001000; // 非批量更新上下文
const RenderContext = /* */ 0b0010000; // 渲染上下文
const CommitContext = /* */ 0b0100000; // 提交上下文
export const RetryAfterError = /* */ 0b1000000; // 错误后再次执行
type RootExitStatus = 0 | 1 | 2 | 3 | 4 | 5;
const RootIncomplete = 0; // 没有完成
const RootFatalErrored = 1; // 致命错误
const RootErrored = 2; // 错误
const RootSuspended = 3; // root具有suspenended
const RootSuspendedWithDelay = 4; // root具有suspenended延迟
const RootCompleted = 5; // 已经完成
// getNextLanes 定义(15)
// 定义 getNextLanes , 当前的root , lanes : 0
// src/react/packages/react-reconciler/src/ReactFiberLane.js
// 获取下一个lanes
export function getNextLanes(root: FiberRoot, wipLanes: Lanes): Lanes {
// Early bailout if there's no pending work left
// 获取pendingLanes
const pendingLanes = root.pendingLanes; // 1 等待的lane
if (pendingLanes === NoLanes) { // 为0
return_highestLanePriority = NoLanePriority; // 0
return NoLanes;
}
let nextLanes = NoLanes; // 0
let nextLanePriority = NoLanePriority; // 0
const expiredLanes = root.expiredLanes; // 0
const suspendedLanes = root.suspendedLanes; // 0
const pingedLanes = root.pingedLanes; // 0
// pendingLanes 非空
// Check if any work has expired.
// 检查任务是否过期了
if (expiredLanes !== NoLanes) { // 是否有任务过期
nextLanes = expiredLanes; // 设置过期的任务有过期
nextLanePriority = return_highestLanePriority = SyncLanePriority; // 15
} else {
// 无任务过期的情况
// Do not work on any idle work until all the non-idle work has finished,
// even if the work is suspended.
// 在完成所有非空闲工作之前,请勿进行任何闲置工作,即使工作是suspended。
// const NonIdleLanes = 0b0000111111111111111111111111111;
const nonIdlePendingLanes = pendingLanes & NonIdleLanes; // 获取非IdleLanes
if (nonIdlePendingLanes !== NoLanes) { // 非空
// suspendedLanes :0
const nonIdleUnblockedLanes = nonIdlePendingLanes & ~suspendedLanes; // 非pendingLanes
if (nonIdleUnblockedLanes !== NoLanes) { // 初始化
// nonIdleUnblockedLanes: 1
nextLanes = getHighestPriorityLanes(nonIdleUnblockedLanes); // 1
nextLanePriority = return_highestLanePriority; // 15
} else {
const nonIdlePingedLanes = nonIdlePendingLanes & pingedLanes;
if (nonIdlePingedLanes !== NoLanes) {
nextLanes = getHighestPriorityLanes(nonIdlePingedLanes);
nextLanePriority = return_highestLanePriority;
}
}
} else {
// 只剩下空闲的工作
// The only remaining work is Idle.
const unblockedLanes = pendingLanes & ~suspendedLanes;
if (unblockedLanes !== NoLanes) {
nextLanes = getHighestPriorityLanes(unblockedLanes);
nextLanePriority = return_highestLanePriority;
} else {
if (pingedLanes !== NoLanes) {
nextLanes = getHighestPriorityLanes(pingedLanes);
nextLanePriority = return_highestLanePriority;
}
}
}
}
// 只有我们是suspended才能到达这里
if (nextLanes === NoLanes) {
// 只有我们是suspended才能到达这里
// This should only be reachable if we're suspended
// TODO: Consider warning in this path if a fallback timer is not scheduled.
return NoLanes;
}
// If there are higher priority lanes, we'll include them even if they
// are suspended.
// 如果有更高优先级的lanes,我们将包含他们即便他们是suspended
nextLanes = pendingLanes & getEqualOrHigherPriorityLanes(nextLanes);
// 1
// pendingLanes
// If we're already in the middle of a render, switching lanes will interrupt
// it and we'll lose our progress. We should only do this if the new lanes are
// higher priority.
// 如果我们已经在渲染中间,切换lanes将会中断他并且我们会失去我们的进度
// 我们只能在新的更高优先级的lanes中做这些
// 传入的lanns 非空, 且不等于nextLanes
if ( wipLanes !== NoLanes && wipLanes !== nextLanes &&
// If we already suspended with a delay, then interrupting is fine. Don't
// bother waiting until the root is complete.
// 如果我们已经suspended了一段时间,那么中断就可以了。别等到根完成为止。
(wipLanes & suspendedLanes) === NoLanes
) {
getHighestPriorityLanes(wipLanes);
const wipLanePriority = return_highestLanePriority;
if (nextLanePriority <= wipLanePriority) {
return wipLanes;
} else {
return_highestLanePriority = nextLanePriority;
}
}
const entangledLanes = root.entangledLanes;
if (entangledLanes !== NoLanes) {
const entanglements = root.entanglements;
let lanes = nextLanes & entangledLanes;
while (lanes > 0) {
const index = pickArbitraryLaneIndex(lanes);
const lane = 1 << index;
nextLanes |= entanglements[index];
lanes &= ~lane;
}
}
return nextLanes;
}
// getHighestPriorityLanes 定义(15)
// 获取最高优先级的lane
// 地址: src/react/packages/react-reconciler/src/ReactFiberLane.js
// 逻辑 获取最高的lanes
function getHighestPriorityLanes(lanes: Lanes | Lane): Lanes {
// 1 非批量同步
if ((SyncLane & lanes) !== NoLanes) { // 1
return_highestLanePriority = SyncLanePriority; // 15
return SyncLane; // 1
}
if ((SyncBatchedLane & lanes) !== NoLanes) { // 2
return_highestLanePriority = SyncBatchedLanePriority; // 14
return SyncBatchedLane;
}
if ((InputDiscreteHydrationLane & lanes) !== NoLanes) { // 4
return_highestLanePriority = InputDiscreteHydrationLanePriority; // 13
return InputDiscreteHydrationLane;
}
const inputDiscreteLanes = InputDiscreteLanes & lanes; // 24
if (inputDiscreteLanes !== NoLanes) {
return_highestLanePriority = InputDiscreteLanePriority;
return inputDiscreteLanes;
}
if ((lanes & InputContinuousHydrationLane) !== NoLanes) {
return_highestLanePriority = InputContinuousHydrationLanePriority;
return InputContinuousHydrationLane;
}
const inputContinuousLanes = InputContinuousLanes & lanes;
if (inputContinuousLanes !== NoLanes) {
return_highestLanePriority = InputContinuousLanePriority;
return inputContinuousLanes;
}
if ((lanes & DefaultHydrationLane) !== NoLanes) {
return_highestLanePriority = DefaultHydrationLanePriority;
return DefaultHydrationLane;
}
const defaultLanes = DefaultLanes & lanes;
if (defaultLanes !== NoLanes) {
return_highestLanePriority = DefaultLanePriority;
return defaultLanes;
}
if ((lanes & TransitionHydrationLane) !== NoLanes) {
return_highestLanePriority = TransitionHydrationPriority;
return TransitionHydrationLane;
}
const transitionLanes = TransitionLanes & lanes;
if (transitionLanes !== NoLanes) {
return_highestLanePriority = TransitionPriority;
return transitionLanes;
}
const retryLanes = RetryLanes & lanes;
if (retryLanes !== NoLanes) {
return_highestLanePriority = RetryLanePriority;
return retryLanes;
}
if (lanes & SelectiveHydrationLane) {
return_highestLanePriority = SelectiveHydrationLanePriority;
return SelectiveHydrationLane;
}
if ((lanes & IdleHydrationLane) !== NoLanes) {
return_highestLanePriority = IdleHydrationLanePriority;
return IdleHydrationLane;
}
const idleLanes = IdleLanes & lanes;
if (idleLanes !== NoLanes) {
return_highestLanePriority = IdleLanePriority;
return idleLanes;
}
if ((OffscreenLane & lanes) !== NoLanes) {
return_highestLanePriority = OffscreenLanePriority;
return OffscreenLane;
}
// This shouldn't be reachable, but as a fallback, return the entire bitmask.
return_highestLanePriority = DefaultLanePriority;
return lanes;
}
// 备注
export const SyncLanePriority: LanePriority = 15;
export const SyncBatchedLanePriority: LanePriority = 14;
const InputDiscreteHydrationLanePriority: LanePriority = 13;
export const InputDiscreteLanePriority: LanePriority = 12;
const InputContinuousHydrationLanePriority: LanePriority = 11;
export const InputContinuousLanePriority: LanePriority = 10;
const DefaultHydrationLanePriority: LanePriority = 9;
export const DefaultLanePriority: LanePriority = 8;
const TransitionHydrationPriority: LanePriority = 7;
export const TransitionPriority: LanePriority = 6;
const RetryLanePriority: LanePriority = 5;
const SelectiveHydrationLanePriority: LanePriority = 4;
const IdleHydrationLanePriority: LanePriority = 3;
const IdleLanePriority: LanePriority = 2;
const OffscreenLanePriority: LanePriority = 1;
export const NoLanePriority: LanePriority = 0;
const TotalLanes = 31;
export const NoLanes: Lanes = /* */ 0b0000000000000000000000000000000;
export const NoLane: Lane = /* */ 0b0000000000000000000000000000000;
export const SyncLane: Lane = /* */ 0b0000000000000000000000000000001;
export const SyncBatchedLane: Lane = /* */ 0b0000000000000000000000000000010;
export const InputDiscreteHydrationLane: Lane = /* */ 0b0000000000000000000000000000100;
const InputDiscreteLanes: Lanes = /* */ 0b0000000000000000000000000011000; // 24
const InputContinuousHydrationLane: Lane = /* */ 0b0000000000000000000000000100000;
const InputContinuousLanes: Lanes = /* */ 0b0000000000000000000000011000000;
export const DefaultHydrationLane: Lane = /* */ 0b0000000000000000000000100000000;
export const DefaultLanes: Lanes = /* */ 0b0000000000000000000111000000000;
const TransitionHydrationLane: Lane = /* */ 0b0000000000000000001000000000000;
const TransitionLanes: Lanes = /* */ 0b0000000001111111110000000000000;
const RetryLanes: Lanes = /* */ 0b0000011110000000000000000000000;
export const SomeRetryLane: Lanes = /* */ 0b0000010000000000000000000000000;
export const SelectiveHydrationLane: Lane = /* */ 0b0000100000000000000000000000000;
const NonIdleLanes = /* */ 0b0000111111111111111111111111111;
export const IdleHydrationLane: Lane = /* */ 0b0001000000000000000000000000000;
const IdleLanes: Lanes = /* */ 0b0110000000000000000000000000000;
export const OffscreenLane: Lane = /* */ 0b1000000000000000000000000000000;
export const NoTimestamp = -1;
// renderRootSync 函数定义(16)
// 处理更新
// 处理更新
//位置 src/react/packages/react-reconciler/src/ReactFiberWorkLoop.old.js
// 逻辑: 开始同步更新
function renderRootSync(root: FiberRoot, lanes: Lanes) {
const prevExecutionContext = executionContext; // 旧的上下文
// 切换到渲染执行上下文
executionContext |= RenderContext; // 添加render // 24
// 初始上下文为8 ,非批量同步: 8 , RenderContext: render: 16
// hooks相关
const prevDispatcher = pushDispatcher();
// If the root or lanes have changed, throw out the existing stack
// and prepare a fresh one. Otherwise we'll continue where we left off.
// 如果root或者lanes改变,丢弃现有的栈
// 而且准备一个新的,否则我们会继续离开我们所在的地方
if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {
// 准备一个当前fiber节点的克隆 放在全局变量workInProgress中
prepareFreshStack(root, lanes);
// 不处理
startWorkOnPendingInteractions(root, lanes);
}
// 函数忽略
const prevInteractions = pushInteractions(root)
// 函数忽略
if (enableSchedulingProfiler) {
markRenderStarted(lanes);
}
do {
try {
// 进行更新, workLook
// 循环处理workInProgress
workLoopSync();
break;
} catch (thrownValue) {
handleError(root, thrownValue);
}
} while (true);
resetContextDependencies();
if (enableSchedulerTracing) {
popInteractions(((prevInteractions: any): Set<Interaction>));
}
// render 过程结束,还原上下文
executionContext = prevExecutionContext;
popDispatcher(prevDispatcher);
// 报错提醒
if (workInProgress !== null) {
// This is a sync render, so we should have finished the whole tree.
invariant(
false,
'Cannot commit an incomplete root. This error is likely caused by a ' +
'bug in React. Please file an issue.',
);
}
// 不处理
if (enableSchedulingProfiler) {
markRenderStopped();
}
// Set this to null to indicate there's no in-progress render.
// 清空 workInProgressRoot 设置为null,比送啊hi没有正在进行的render
workInProgressRoot = null; // 清空 workInProgressRoot
workInProgressRootRenderLanes = NoLanes;
// workInProgressRootRenderLanes 也清空
return workInProgressRootExitStatus; // 返回执行结果
}
// pushInteractions定义
function pushInteractions(root) {
// 不处理enableSchedulerTracing
if (enableSchedulerTracing) {
const prevInteractions: Set<Interaction> | null = __interactionsRef.current;
__interactionsRef.current = root.memoizedInteractions;
return prevInteractions;
}
return null;
}
// 定义prepareFreshStack (17)
// src/react/packages/react-reconciler/src/ReactFiberWorkLoop.old.js
// 逻辑, 获取从current 到workIngProgess 和workInProgresssRoot
// workInProgressRootRenderLanes 和subtreeRenderLanes,
// workInProgressRootIncludedLanes 设置为lanes
function prepareFreshStack(root: FiberRoot, lanes: Lanes) {
root.finishedWork = null; // 设置为空
root.finishedLanes = NoLanes; // 完成的lanes
// 初始root.timeoutHandle -1
const timeoutHandle = root.timeoutHandle; // 获取当前的timeoutHander
if (timeoutHandle !== noTimeout) {
// NoTimeout = -1;
// The root previous suspended and scheduled a timeout to commit a fallback
// state. Now that we have additional work, cancel the timeout.
root.timeoutHandle = noTimeout; // 清空
// $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above
cancelTimeout(timeoutHandle); // 取消
}
// workInProgress 不为空, 有任务没有完成
if (workInProgress !== null) {
let interruptedWork = workInProgress.return;
while (interruptedWork !== null) {
unwindInterruptedWork(interruptedWork);
interruptedWork = interruptedWork.return;
}
}
//
workInProgressRoot = root; // 赋值 fiberRoot
// 创建workInProgress, root.current rootFiber
workInProgress = createWorkInProgress(root.current, null);
// 我们使用双重缓冲池技术
// 因为我们知道我们最多需要一颗数的两个版本
// 我们将"其他"未使用的资源合并这样我们就可以自由的重用其他节点
// 这个懒创建是为了避免分配额外的一些永不更新的对象
// 如果需要,这也允许我们回收额外的内存
// 更新lanes
workInProgressRootRenderLanes = subtreeRenderLanes = workInProgressRootIncludedLanes = lanes;
workInProgressRootExitStatus = RootIncomplete;
workInProgressRootFatalError = null;
workInProgressRootSkippedLanes = NoLanes;
workInProgressRootUpdatedLanes = NoLanes;
workInProgressRootPingedLanes = NoLanes;
if (enableSchedulerTracing) {
spawnedWorkDuringRender = null;
}
}
// createWorkInProgress 定义(18)
// src/react/packages/react-reconciler/src/ReactFiber.old.js
// This is used to create an alternate fiber to do work on.
// 创建alternate fiber, 由当前的fiber 创建workInProgress
export function createWorkInProgress(current: Fiber, pendingProps: any): Fiber {
// current 当前的fiber,
let workInProgress = current.alternate;
// 不存在
if (workInProgress === null) {
// We use a double buffering pooling technique because we know that we'll
// only ever need at most two versions of a tree. We pool the "other" unused
// node that we're free to reuse. This is lazily created to avoid allocating
// extra objects for things that are never updated. It also allow us to
// reclaim the extra memory if needed.
workInProgress = createFiber(
current.tag, //tag
pendingProps, // 更新的props
current.key, // key
current.mode, // modl
);
workInProgress.elementType = current.elementType;
workInProgress.type = current.type;
workInProgress.stateNode = current.stateNode;
workInProgress.alternate = current; // 指向当前
current.alternate = workInProgress; // 当前的
} else {
// 如果存在,
workInProgress.pendingProps = pendingProps; /// 更新
// Needed because Blocks store data on type.
workInProgress.type = current.type;
// We already have an alternate.
// Reset the effect tag.
workInProgress.flags = NoFlags;
// The effect list is no longer valid.
workInProgress.nextEffect = null; // 副作用
workInProgress.firstEffect = null;
workInProgress.lastEffect = null;
// 不处理
if (enableProfilerTimer) {
// We intentionally reset, rather than copy, actualDuration & actualStartTime.
// This prevents time from endlessly accumulating in new commits.
// This has the downside of resetting values for different priority renders,
// But works for yielding (the common case) and should support resuming.
workInProgress.actualDuration = 0;
workInProgress.actualStartTime = -1;
}
}
// 更新childLanes
workInProgress.childLanes = current.childLanes;
workInProgress.lanes = current.lanes;
workInProgress.child = current.child;
workInProgress.memoizedProps = current.memoizedProps;
workInProgress.memoizedState = current.memoizedState;
workInProgress.updateQueue = current.updateQueue;
// Clone the dependencies object. This is mutated during the render phase, so
// it cannot be shared with the current fiber.
const currentDependencies = current.dependencies;
workInProgress.dependencies =
currentDependencies === null
? null
: {
lanes: currentDependencies.lanes,
firstContext: currentDependencies.firstContext,
};
// These will be overridden during the parent's reconciliation
workInProgress.sibling = current.sibling;
workInProgress.index = current.index;
workInProgress.ref = current.ref;
if (enableProfilerTimer) {
workInProgress.selfBaseDuration = current.selfBaseDuration;
workInProgress.treeBaseDuration = current.treeBaseDuration;
}
return workInProgress;
}
// workLoopSync 定义(19)
// 新操作
// src/react/packages/react-reconciler/src/ReactFiberWorkLoop.old.js
// 循环遍历performUnitOfWork, 同步更新
function workLoopSync() {
/*
performUnitOfWork 方法循环调用 beginWork 找到处理对应组件的 hander 方法
采用深度优先(先序优先)的方式遍历创建子节点,遇到同级节点下有多个子节点时,会为每
个节点创建一个 sibling 属性指向下一个同级节点
当遍历到某个分支的最深节点(没有子节点)时调用 completeUnitOfWork 方法
completeUnitOfWork 方法判断如果有 sibling(下一个同级节点)则返回给 performUnitOfWork
没有 sibling 则寻找 return(父节点),如果父节点有 sibling 继续返回给 performUnitOfWork
从而实现深度优先遍历去创建整个 Fiber tree
*/
// Already timed out, so perform work without checking if we need to yield.
// 是否具有fiber, 时间已经结束,
while (workInProgress !== null) { // 同步更新的时候,一次性更新完
// 执行更新操作
performUnitOfWork(workInProgress); // rootFiber的alternate
}
}
// performUnitOfWork(20)
// 执行更新的操作
// src/react/packages/react-reconciler/src/ReactFiberWorkLoop.old.js
// h
function performUnitOfWork(unitOfWork: Fiber): void {
// The current, flushed, state of this fiber is the alternate. Ideally
// nothing should rely on this, but relying on it here means that we don't
// need an additional field on the work in progress.
// 创建一个备份的fiber
// 最理想的情况是不依靠current fiber, 创建一个workInProgress
// 创建一个workInProgress的alternate属性指向current fiber
const current = unitOfWork.alternate; // current
setCurrentDebugFiberInDEV(unitOfWork);
let next;
// ProfileMode 模式问题, ProfileMode 模式下
if (enableProfilerTimer && (unitOfWork.mode & ProfileMode) !== NoMode) {
startProfilerTimer(unitOfWork);
next = beginWork(current, unitOfWork, subtreeRenderLanes);
stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true);
} else {
// 正常的流程
// 已经使用的fiber, 更新的fiber, subtreeRenderLanes: 当前的的lane
next = beginWork(current, unitOfWork, subtreeRenderLanes);
}
resetCurrentDebugFiberInDEV();
unitOfWork.memoizedProps = unitOfWork.pendingProps;
if (next === null) {
// If this doesn't spawn new work, complete the current work.
// 进行共搜
// 如果没有分配新的工作,完成当前工作
completeUnitOfWork(unitOfWork);
} else {
// 如果具有
// workInProgress设置为一下个工作
workInProgress = next;
}
ReactCurrentOwner.current = null;
}
// 定义completeUnitOfWork
/*
功能:
① 协助 workLoopSync 深度优先(先序优先)遍历生成 Fiber 树,原理:
当 workLoopSync 遍历到当前分支最深的节点时向上寻找父节点并判断父节点有无同级节点,
有的话将 workInProgress 其设置为此节点,从而实现寻找下一个节点
② 判断 effectTag 创建副作用链表(由子结点往上指向父节点)
③ 调用 completeWork 方法
疑问 ① 为什要创建副作用链表 答:当项目复杂时 Fiber 树拥有很多很多的节点,
如果通过遍历每个节点的方式去运行当前节点副作用的话时间复杂度会上升,
所以在构建树的时候通过判断每个节点的 effectTag
将副作用关联起来生成一个链表可以有效的降低时间复杂度提升程序效率。
疑问 ② 为什么子结点的副作用要排在父节点的副作用之前:
答:副作用处理 componentDidMount 生命周期和 ref,
根据生命周期 componentDidMount 的定义可以知道只有当子组件渲染完成时,
父组件的 componentDidMount 生命周期才会被调用,所以子组件的 componentDidMount
生命周期运行一定在父组件之前,因此副作用链表排序是符合功能实现的,ref 方法也同理,
父组件通过子组件的 ref 获取实例时应该确保子组件的 ref 已经被处理。
*/
图片总结:
1, 初次渲染的时候,为了更快显示页面,使用非批量进行更新。通过设置context 进行配置,vuex中的commit也使用类似方式。
2,16版本使用过期时间判断,17版本使用Lanes 进行判断。
更多推荐
所有评论(0)