react源码中的协调与调度

requestEventTime

其实在React执行过程中,会有数不清的任务要去执行,但是他们会有一个优先级的判定,假如两个事件的优先级一样,那么React是怎么去判定他们两谁先执行呢?

// packages/react-reconciler/src/ReactFiberWorkLoop.old.js
export function requestEventTime() {if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {// We're inside React, so it's fine to read the actual time.// react事件正在执行// executionContext// RenderContext 正在计算// CommitContext 正在提交// 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;return now();}// 没有在react事件执行 NoTimestamp === -1if (currentEventTime !== NoTimestamp) { // 浏览器事件正在执行,返回上次的 currentEventTimereturn currentEventTime;}// 重新计算currentEventTime,当执行被中断后currentEventTime = now();return currentEventTime;
} 
  • RenderContextCommitContext表示正在计算更新和正在提交更新,返回now()
  • 如果是浏览器事件正在执行中,返回上一次的currentEventTime
  • 如果终止或者中断react任务执行的时候,则重新获取执行时间now()。
  • 获取的时间越小,则执行的优先级越高

now()并不是单纯的new Date(),而是判定两次更新任务的时间是否小于10ms,来决定是否复用上一次的更新时间Scheduler_now的。

export const now = initialTimeMs < 10000 ? Scheduler_now : () => Scheduler_now() - initialTimeMs; 

其实各位猜想一下,对于10ms级别的任务间隙时间,几乎是可以忽略不计的,那么这里就可以视为同样的任务,不需要有很大的性能开销,有利于批量更新

requestUpdateLane

requestEventTime位每一个需要执行的任务打上了触发更新时间标签,那么任务的优先级还需要进一步的确立,requestUpdateLane就是用来获取每一个任务执行的优先级的。

// packages/react-reconciler/src/ReactFiberWorkLoop.old.js
export function requestUpdateLane(fiber: Fiber): Lane {// Special casesconst mode = fiber.mode;if ((mode & BlockingMode) === NoMode) {return (SyncLane: Lane);} else if ((mode & ConcurrentMode) === NoMode) {return getCurrentPriorityLevel() === ImmediateSchedulerPriority? (SyncLane: Lane): (SyncBatchedLane: Lane);} else if (!deferRenderPhaseUpdateToNextBatch &&(executionContext & RenderContext) !== NoContext &&workInProgressRootRenderLanes !== NoLanes) {// This is a render phase update. These are not officially supported. The// old behavior is to give this the same "thread" (expiration time) as// whatever is currently rendering. So if you call `setState` on a component// that happens later in the same render, it will flush. Ideally, we want to// remove the special case and treat them as if they came from an// interleaved event. Regardless, this pattern is not officially supported.// This behavior is only a fallback. The flag only exists until we can roll// out the setState warning, since existing code might accidentally rely on// the current behavior.return pickArbitraryLane(workInProgressRootRenderLanes);}// The algorithm for assigning an update to a lane should be stable for all// updates at the same priority within the same event. To do this, the inputs// to the algorithm must be the same. For example, we use the `renderLanes`// to avoid choosing a lane that is already in the middle of rendering. However, the "included" lanes could be mutated in between updates in the// same event, like if you perform an update inside `flushSync`. Or any other// code path that might call `prepareFreshStack`. The trick we use is to cache the first of each of these inputs within an// event. Then reset the cached values once we can be sure the event is over.// Our heuristic for that is whenever we enter a concurrent work loop. 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();// The old behavior was using the priority level of the Scheduler.// This couples React to the Scheduler internals, so we're replacing it// with the currentUpdateLanePriority above. As an example of how this// could be problematic, if we're not inside `Scheduler.runWithPriority`,// then we'll get the priority of the current running Scheduler task,// which is probably not what we want.let lane;if (// TODO: Temporary. We're removing the concept of discrete updates.(executionContext & DiscreteEventContext) !== NoContext &&// 用户block的类型事件schedulerPriority === UserBlockingSchedulerPriority) {// 通过findUpdateLane函数重新计算lanelane = findUpdateLane(InputDiscreteLanePriority, currentEventWipLanes);} else {// 根据优先级计算法则计算laneconst schedulerLanePriority = schedulerPriorityToLanePriority(schedulerPriority,);if (decoupleUpdatePriorityFromScheduler) {// In the new strategy, we will track the current update lane priority// inside React and use that priority to select a lane for this update.// For now, we're just logging when they're different so we can assess.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,);}}}// 根据计算得到的 schedulerLanePriority,计算更新的优先级 lanelane = findUpdateLane(schedulerLanePriority, currentEventWipLanes);}return lane;
} 
  • 通过getCurrentPriorityLevel获得所有执行任务的调度优先级schedulerPriority
  • 通过findUpdateLane计算lane,作为更新中的优先级。

findUpdateLane

export function findUpdateLane( lanePriority: LanePriority,wipLanes: Lanes, ): Lane {switch (lanePriority) {case NoLanePriority:break;case SyncLanePriority:return SyncLane;case SyncBatchedLanePriority:return SyncBatchedLane;case InputDiscreteLanePriority: {const lane = pickArbitraryLane(InputDiscreteLanes & ~wipLanes);if (lane === NoLane) {// Shift to the next priority levelreturn findUpdateLane(InputContinuousLanePriority, wipLanes);}return lane;}case InputContinuousLanePriority
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值