优先级

lane 优先级

在 React lanes 模型是 31 个二进制通道。以 1 的位置表示当前更新的优先级,全为 0 时表示没有更新。优先级从右往左依次降低。

如下图所示:

事件优先级

事件优先级有以下几种:

ini 复制代码
export const DiscreteEventPriority = SyncLane;
export const ContinuousEventPriority = InputContinuousLane;
export const DefaultEventPriority = DefaultLane;
export const IdleEventPriority = IdleLane;

可以看到,事件优先级的值其实就是对应的 lane 优先级。由于 react 是合成事件,所以在触发事件时,会调用 setCurrentUpdatePriority 函数,将优先级设置为当前事件对应优先级,方便调用。

js 复制代码
export function getEventPriority(domEventName: DOMEventName): * {
  switch (domEventName) {
    // 删除其他事件
    // ...
    case 'click':
      return DiscreteEventPriority;
    case 'drag':
      return ContinuousEventPriority;
    default:
      return DefaultEventPriority;
  }
}

getEventPriority 函数根据事件名返回不同的事件优先级。

这个函数在创建事件监听函数时会调用,获取当前事件对应的事件优先级。

ini 复制代码
export function createEventListenerWrapperWithPriority(
  targetContainer: EventTarget,
  domEventName: DOMEventName,
  eventSystemFlags: EventSystemFlags,
): Function {
  const eventPriority = getEventPriority(domEventName);
  let listenerWrapper;
  switch (eventPriority) {
    case DiscreteEventPriority:
      listenerWrapper = dispatchDiscreteEvent;
      break;
    case ContinuousEventPriority:
      listenerWrapper = dispatchContinuousEvent;
      break;
    case DefaultEventPriority:
    default:
      listenerWrapper = dispatchEvent;
      break;
  }
  return listenerWrapper.bind(
    null,
    domEventName,
    eventSystemFlags,
    targetContainer,
  );
}
function dispatchDiscreteEvent(
  domEventName,
  eventSystemFlags,
  container,
  nativeEvent,
) {
  const previousPriority = getCurrentUpdatePriority();
  const prevTransition = ReactCurrentBatchConfig.transition;
  ReactCurrentBatchConfig.transition = null;
  try {
    setCurrentUpdatePriority(DiscreteEventPriority);
    dispatchEvent(domEventName, eventSystemFlags, container, nativeEvent);
  } finally {
    setCurrentUpdatePriority(previousPriority);
    ReactCurrentBatchConfig.transition = prevTransition;
  }
}

需要注意的是 getCurrentUpdatePriority 和 setCurrentUpdatePriority,这两个函数操作的一个全局变量 currentUpdatePriority。这个变量缓存了当前更新的优先级。

在调用 setState(这里举个例子,其实不止这个函数) 函数时,就可以调用 requestUpdateLane 获取当前优先级。

js 复制代码
export function requestUpdateLane(fiber: Fiber): Lane {
  // ...
  const updateLane: Lane = (getCurrentUpdatePriority(): any);
  if (updateLane !== NoLane) {
    return updateLane;
  }
  const eventLane: Lane = (getCurrentEventPriority(): any);
  return eventLane;
}

requestUpdateLane 先从 getCurrentUpdatePriority 函数获取优先级,如果存在则直接返回,不存在则返回事件优先级。

最后在创建更新时,就有了优先级,于是创建的更新队列也就有了优先级。

如图所示:

这是加了优先级之后的更新链表。为了实现高优先级先执行,还需要维护一个链表。这个链表是实际执行的链表。为此需要在更新队列对象中增加几个参数。

js 复制代码
function initializeUpdateQueue(fiber) {
  const queue = {
    baseState: fiber.memoizedState, //本次更新前该Fiber节点的state,Update基于该state计算更新后的state
    firstBaseUpdate: null, //本次更新前该Fiber节点已保存的Update链表头
    lastBaseUpdate: null, //本次更新前该Fiber节点已保存的Update链表尾
    shared: {
      //触发更新时,产生的Update会保存在shared.pending中形成单向环状链表
      //当由Update计算state时这个环会被剪开并连接在lastBaseUpdate后面
      pending: null,
    },
  };
  fiber.updateQueue = queue;
}

老更新队列为空示例图:

老更新队列不为空示意图:

由上图所示,当更新队列执行时,实际执行的队列为 firstBaseUpdate 开头到 lastBaseUpdate 结束的更新队列。

当更新优先级低于渲染优先级时,该更新会被跳过,并将 firstBaseUpdate 指向该更新,继续遍历链表,将 lastBaseUpdate 指向链表尾部。

在下一次更新时,先合并链表,再根据优先级执行。

源码在 /Users/sunxianfu/Desktop/Project/react/packages/react-reconciler/src/ReactFiberClassUpdateQueue.old.js。

相关推荐
kiracrimson2 小时前
npm 入门:包管理器、依赖与 npx
前端·npm·node.js
ShineWinsu3 小时前
对于JavaScript:初识JavaScript以及输入输出
java·开发语言·前端·javascript·css·面试·html
鲤鱼_5993 小时前
教培机构一体化运营管理系统操作手册
前端
鶴哥只手遮天3 小时前
React 19.3.1 源码深度剖析-第 3 章 Fiber 架构与双缓冲
前端·react.js·开源
鶴哥只手遮天3 小时前
React 19.3.1 源码深度剖析-第 9 章(下)lazy、retry、hydration 与实战
前端·react.js·开源
鶴哥只手遮天3 小时前
React 19.3.1 源码深度剖析-第 6 章 React DOM 渲染器与 Commit 阶段(把 Fiber 副作用落到真实 DOM)(上)
前端·react.js·开源
鶴哥只手遮天3 小时前
React 19.3.1 源码深度剖析-第 6 章 React DOM 渲染器与 Commit 阶段(把 Fiber 副作用落到真实 DOM)(下)
前端·react.js·开源
鶴哥只手遮天3 小时前
React 19.3.1 源码深度剖析-第 13 章:React 19 新特性深解
前端·react.js·开源
donk13143 小时前
React Native for OpenHarmony 实战:三方库 react-native-circular-action-menu 的鸿蒙化适配指南
javascript·分布式·react native·react.js·wpf·harmonyos
鶴哥只手遮天3 小时前
React 19.3.1 源码深度剖析-第 1 章 总览与架构哲学
前端·react.js·开源