React中的更新优先级
1. 优先级分类
React 中的更新优先级分为事件优先级、更新优先级和调度优先级三种。其中,事件优先级和更新优先级是由 React 自身的内部机制决定的。
2. lane 模型
React 中的 Lane 模型是 React 内部优先级系统的核心部分。Lane 模型的目的是为了避免低优先级的更新被高优先级的更新所阻塞,从而保证应用的响应性和性能。Lane 模型通过将任务分为不同的更新类型和优先级,使得 React 能够对任务进行优先级管理和调度。
在 React 内部凡是涉及到优先级调度的地方,都会使用 unstable_runWithPriority。
首先将 Lane 模型的优先级转换为 React Event 的优先级,因为他们的值都是 Lane 值,所以只需要做个多对少的映射就好了。然后将 React Event 优先级映射到 scheduler 的优先级,再调用 scheduler 的调度函数scheduleCallback完成一次调度下发:
在 ensureRootIsScheduled 函数中,React 会判断当前任务是同步任务还是异步任务。如果是同步任务,React 会直接加入更新队列,否则将任务按照优先级进行调度。React 使用 Scheduler 模块来进行任务调度,其中 scheduleCallback 函数会将任务添加到任务最小堆中。在任务的过期时间到达后,React 会执行任务回调函数。
//离散事件优先级 click onchange
export const DiscreteEventPriority = SyncLane; //1
//连续事件的优先级 mousemove
export const ContinuousEventPriority = InputContinuousLane; //4
//默认事件车道
export const DefaultEventPriority = DefaultLane; //16
//空闲事件优先级
export const IdleEventPriority = IdleLane; //
//判断事件优先级是不是比lane优先级小,小则优先级高
export function isHigherEventPriority(eventPriority, lane) {
return eventPriority !== 0 && eventPriority < lane;
}
// 将lane模型中的优先级转换为事件优先级
export function lanesToEventPriority(lanes) {
//获取最高优先级的lane
let lane = getHighestPriorityLane(lanes);
if (!isHigherEventPriority(DiscreteEventPriority, lane)) {
return DiscreteEventPriority; //1
}
if (!isHigherEventPriority(ContinuousEventPriority, lane)) {
return ContinuousEventPriority; //4
}
if (includesNonIdleWork(lane)) {
return DefaultEventPriority; //16
}
return IdleEventPriority; //
}
// 在ReactFiberWorkLoop文件中,判断是否是同步任务,异步时转换优先级
function ensureRootIsScheduled(root, currentTime) {
// 获取根上的任务,将已经过期的标记为过期,
// 获取当前优先级最高的任务,并获取优先级,和根上在执行的任务对比优先级,/如果新的优先级和老的优先级一样,则可以进行批量更新
// 如果没有要执行的任务,返回
/**
* 省略部分代码
* */
// 如果是同步任务,加入更新队列
//如果不是同步,就需要调度一个新的任务
let schedulerPriorityLevel;
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;
}
newCallbackNode = Scheduler_scheduleCallback(
schedulerPriorityLevel,
performConcurrentWorkOnRoot.bind(null, root)//performConcurrentWorkOnRoot方法为beginWork后面继续这部分
);
}
//Scheduler.js
export const scheduleCallback = Scheduler.unstable_scheduleCallback;
function scheduleCallback(priorityLevel, callback) {
// 获取当前的时候
const currentTime = getCurrentTime();
// 此任务的开时间
const startTime = currentTime;
//超时时间
let timeout;
//根据优先级计算过期的时间
switch (priorityLevel) {
case ImmediatePriority:
timeout = IMMEDIATE_PRIORITY_TIMEOUT; // -1
break;
case UserBlockingPriority:
timeout = USER_BLOCKING_PRIORITY_TIMEOUT; // 250ms
break;
case IdlePriority:
timeout = IDLE_PRIORITY_TIMEOUT; //1073741823
break;
case LowPriority:
timeout = LOW_PRIORITY_TIMEOUT; //10000
break;
case NormalPriority:
default: //5000
timeout = NORMAL_PRIORITY_TIMEOUT;
break;
}
//计算此任务的过期时间
const expirationTime = startTime + timeout;
const newTask = {
id: taskIdCounter++,
callback, //回调函数或者说任务函数
priorityLevel, //优先级别
startTime, //任务的开始时间
expirationTime, //任务的过期时间
sortIndex: expirationTime, //排序依赖
};
//向任务最小堆里添加任务,排序的依据是过期时间
push(taskQueue, newTask);
//flushWork执行工作,刷新工作,执行任务
requestHostCallback(workLoop);
return newTask;
}
小结
总之,在 React 中,Lane 模型和 Scheduler 模块是实现高效更新机制的关键。它们通过对任务进行优先级管理和调度,使得 React 能够在保证应用响应性和性能的前提下,尽可能地将更新任务分散到多个帧中,从而提高应用的运行效率和用户体验。
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第5天,点击查看活动详情