您现在的位置是:网站首页> 编程资料编程资料
react源码层分析协调与调度_React_
2023-05-24
334人已围观
简介 react源码层分析协调与调度_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 === -1 if (currentEventTime !== NoTimestamp) { // 浏览器事件正在执行,返回上次的 currentEventTime return currentEventTime; } // 重新计算currentEventTime,当执行被中断后 currentEventTime = now(); return currentEventTime; }RenderContext与CommitContext表示正在计算更新和正在提交更新,返回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 cases const 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函数重新计算lane lane = findUpdateLane(InputDiscreteLanePriority, currentEventWipLanes); } else { // 根据优先级计算法则计算lane const 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,计算更新的优先级 lane lane = 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 level return findUpdateLane(InputContinuousLanePriority, wipLanes); } return lane; } case InputContinuousLanePriority: { const lane = pickArbitraryLane(InputContinuousLanes & ~wipLanes); if (lane === NoLane) { // Shift to the next priority level return findUpdateLane(DefaultLanePriority, wipLanes); } return lane; } case DefaultLanePriority: { let lane = pickArbitraryLane(DefaultLanes & ~wipLanes); if (lane === NoLane) { // If all the default lanes are already being worked on, look for a // lane in the transition range. lane = pickArbitraryLane(TransitionLanes & ~wipLanes); if (lane === NoLane) { // All the transition lanes are taken, too. This should be very // rare, but as a last resort, pick a default lane. This will have // the effect of interrupting the current work-in-progress render. lane = pickArbitraryLane(DefaultLanes); } } return lane; } case TransitionPriority: // Should be handled by findTransitionLane instead case RetryLanePriority: // Should be handled by findRetryLane instead break; case IdleLanePriority: let lane = pickArbitraryLane(IdleLanes & ~wipLanes); if (lane === NoLane) { lane = pickArbitraryLane(IdleLanes); } return lane; default: // The remaining priorities are not valid for updates break; } invariant( false, 'Invalid update priority: %s. This is a bug in React.', lanePriority, ); }相关参考视频讲解:进入学习
lanePriority LanePriority
export opaque type LanePriority = | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17; export opaque type Lanes = number; export opaque type Lane = number; export opaque type LaneMap= Array ; import { ImmediatePriority as ImmediateSchedulerPriority, UserBlockingPriority as UserBlockingSchedulerPriority, NormalPriority as NormalSchedulerPriority, LowPriority as LowSchedulerPriority, IdlePriority as IdleSchedulerPriority, NoPriority as NoSchedulerPriority, } from './SchedulerWithReactIntegration.new'; // 同步任务 export const SyncLanePriority: La
相关内容
- Node.js中http模块和导出共享问题_node.js_
- JS面试之console的异步性怎么理解详解_javascript技巧_
- react源码层深入刨析babel解析jsx实现_React_
- vue2 webpack proxy与nginx配置方式_vue.js_
- JavaScript利用canvas实现炫酷的碎片切图效果_javascript技巧_
- vue实现超过两行显示展开收起的代码_vue.js_
- 解决找不到模块“xxx.vue”或其相应的类型声明问题_vue.js_
- ant design vue 清空upload组件图片缓存的问题_vue.js_
- uniapp表单验证方法详解_javascript技巧_
- 使用jQuery实现简单穿梭框方式_jquery_
点击排行
本栏推荐
