时间切片的实现和调度(原创2.6万字) (3)

scheduleInteractions 会利用FiberRoot的 pendingInteractionMap 属性和不同的 expirationTime,获取每次schedule所需的update任务的集合,记录它们的数量,并检测这些任务是否会出错。

更新的重点在于 scheduleUpdateOnFiber 每一次更新都会调用 function ensureRootIsScheduled(root: FiberRoot)

下面是 ensureRootIsScheduled 的源码

源码文件

function ensureRootIsScheduled(root: FiberRoot) { const lastExpiredTime = root.lastExpiredTime; if (lastExpiredTime !== NoWork) { // Special case: Expired work should flush synchronously. root.callbackExpirationTime = Sync; root.callbackPriority_old = ImmediatePriority; root.callbackNode = scheduleSyncCallback( performSyncWorkOnRoot.bind(null, root), ); return; } const expirationTime = getNextRootExpirationTimeToWorkOn(root); const existingCallbackNode = root.callbackNode; if (expirationTime === NoWork) { // There's nothing to work on. if (existingCallbackNode !== null) { root.callbackNode = null; root.callbackExpirationTime = NoWork; root.callbackPriority_old = NoPriority; } return; } // TODO: If this is an update, we already read the current time. Pass the // time as an argument. const currentTime = requestCurrentTimeForUpdate(); const priorityLevel = inferPriorityFromExpirationTime( currentTime, expirationTime, ); // If there's an existing render task, confirm it has the correct priority and // expiration time. Otherwise, we'll cancel it and schedule a new one. if (existingCallbackNode !== null) { const existingCallbackPriority = root.callbackPriority_old; const existingCallbackExpirationTime = root.callbackExpirationTime; if ( // Callback must have the exact same expiration time. existingCallbackExpirationTime === expirationTime && // Callback must have greater or equal priority. existingCallbackPriority >= priorityLevel ) { // Existing callback is sufficient. return; } // Need to schedule a new task. // TODO: Instead of scheduling a new task, we should be able to change the // priority of the existing one. cancelCallback(existingCallbackNode); } root.callbackExpirationTime = expirationTime; root.callbackPriority_old = priorityLevel; let callbackNode; if (expirationTime === Sync) { // Sync React callbacks are scheduled on a special internal queue callbackNode = scheduleSyncCallback(performSyncWorkOnRoot.bind(null, root)); } else if (disableSchedulerTimeoutBasedOnReactExpirationTime) { callbackNode = scheduleCallback( priorityLevel, performConcurrentWorkOnRoot.bind(null, root), ); } else { callbackNode = scheduleCallback( priorityLevel, performConcurrentWorkOnRoot.bind(null, root), // Compute a task timeout based on the expiration time. This also affects // ordering because tasks are processed in timeout order. {timeout: expirationTimeToMs(expirationTime) - now()}, ); } root.callbackNode = callbackNode; }

上面源码 ensureRootIsScheduled 主要是根据同步/异步状态做不同的 push 功能。

同步调度 function scheduleSyncCallback(callback: SchedulerCallback) :

如果队列不为空就推入同步队列(syncQueue.push(callback))

如果为空就立即推入 任务调度队列(Scheduler_scheduleCallback)

会将 performSyncWorkOnRoot 作为 SchedulerCallback

下面是 scheduleSyncCallback 源码内容

源码文件

export function scheduleSyncCallback(callback: SchedulerCallback) { // Push this callback into an internal queue. We'll flush these either in // the next tick, or earlier if something calls `flushSyncCallbackQueue`. if (syncQueue === null) { syncQueue = [callback]; // Flush the queue in the next tick, at the earliest. immediateQueueCallbackNode = Scheduler_scheduleCallback( Scheduler_ImmediatePriority, flushSyncCallbackQueueImpl, ); } else { // Push onto existing queue. Don't need to schedule a callback because // we already scheduled one when we created the queue. syncQueue.push(callback); } return fakeCallbackNode; }

异步调度,异步的任务调度很简单,直接将异步任务推入调度队列(Scheduler_scheduleCallback),会将 performConcurrentWorkOnRoot 作为 SchedulerCallback

export function scheduleCallback( reactPriorityLevel: ReactPriorityLevel, callback: SchedulerCallback, options: SchedulerCallbackOptions | void | null, ) { const priorityLevel = reactPriorityToSchedulerPriority(reactPriorityLevel); return Scheduler_scheduleCallback(priorityLevel, callback, options); }

不管同步调度还是异步调度,都会经过 Scheduler_scheduleCallback 也就是调度的核心方法 function unstable_scheduleCallback(priorityLevel, callback, options),它们会有各自的 SchedulerCallback

小提示:由于下面很多代码中会使用 peek,先插一段 peek 实现,其实就是返回数组中的第一个 或者 null

peek 相关源码文件

export function peek(heap: Heap): Node | null { const first = heap[0]; return first === undefined ? null : first; }

下面是 Scheduler_scheduleCallback 相关源码

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsfxjf.html