想想react会怎么做(5)之 Lane

155 阅读11分钟

前言

上节我们在讲updateContainer的时候,我们通过requestUpdateLane(current)创建一个lane,然后将这个lane传入了updateContainerImpl方法中,而updateContainerImpl中又将lane传入了createUpdate方法来创建一个新的更新,所以lane是什么呢?

其实它就是react中的优先级模型,react会对应不同的任务给予不同的优先级,这样react就知道哪些任务更加重要,需要优先做,哪些没那么重要,可以慢点做,而高优先级的任务是可以打断低优先级的任务的

而它的本质就是一个31位的二进制,所以react中就可以有31种优先级

比如说: 0b0000000000000000000000000000000就代表NoLane,也就是没有优先级, 0b0000000000000000000000000000010代表SyncLane,也就是同步优先级。

为什么用二进制

因为二进制能直接使用位运算,性能好,可以用一个值很好的表示lane的集合lanes

比如:0b0000000000000000000000000000011就代表了0b0000000000000000000000000000010和

0b0000000000000000000000000000001的叠加态

那么0b0000000000000000000000000000011就是一个lanes

有哪些lane和lanes

lane的主要逻辑在:packages/react-reconciler/src/ReactFiberLane.js

这里我贴出react中所有的lane和lanes声明

// 总lane的数量
export const TotalLanes = 31;

// 没有lanes
export const NoLanes: Lanes = 0b0000000000000000000000000000000;
// 没有lane
export const NoLane: Lane = 0b0000000000000000000000000000000;

// 同步水合lane
export const SyncHydrationLane: Lane = 0b0000000000000000000000000000001;
// 同步lane
export const SyncLane: Lane = 0b0000000000000000000000000000010;

// 持续输入水合lane
export const InputContinuousHydrationLane: Lane = 0b0000000000000000000000000000100;

// 持续输入lane
export const InputContinuousLane: Lane = 0b0000000000000000000000000001000;

// 默认水合lane
export const DefaultHydrationLane: Lane = 0b0000000000000000000000000010000;

// 默认lane
export const DefaultLane: Lane = 0b0000000000000000000000000100000;

// 同步更新lanes
export const SyncUpdateLanes: Lane = enableUnifiedSyncLane
  ? SyncLane | InputContinuousLane | DefaultLane
  : SyncLane;

const TransitionHydrationLane: Lane = 
                               0b0000000000000000000000001000000;
const TransitionLanes: Lanes = 0b0000000001111111111111110000000;
const TransitionLane1: Lane =  0b0000000000000000000000010000000;
const TransitionLane2: Lane =  0b0000000000000000000000100000000;
const TransitionLane3: Lane =  0b0000000000000000000001000000000;
const TransitionLane4: Lane =  0b0000000000000000000010000000000;
const TransitionLane5: Lane =  0b0000000000000000000100000000000;
const TransitionLane6: Lane =  0b0000000000000000001000000000000;
const TransitionLane7: Lane =  0b0000000000000000010000000000000;
const TransitionLane8: Lane =  0b0000000000000000100000000000000;
const TransitionLane9: Lane =  0b0000000000000001000000000000000;
const TransitionLane10: Lane = 0b0000000000000010000000000000000;
const TransitionLane11: Lane = 0b0000000000000100000000000000000;
const TransitionLane12: Lane = 0b0000000000001000000000000000000;
const TransitionLane13: Lane = 0b0000000000010000000000000000000;
const TransitionLane14: Lane = 0b0000000000100000000000000000000;
const TransitionLane15: Lane = 0b0000000001000000000000000000000;

const RetryLanes: Lanes= 0b0000011110000000000000000000000;
const RetryLane1: Lane = 0b0000000010000000000000000000000;
const RetryLane2: Lane = 0b0000000100000000000000000000000;
const RetryLane3: Lane = 0b0000001000000000000000000000000;
const RetryLane4: Lane = 0b0000010000000000000000000000000;

export const SomeRetryLane: Lane = RetryLane1;

export const SelectiveHydrationLane: Lane = 
                            0b0000100000000000000000000000000;

const NonIdleLanes: Lanes = 0b0000111111111111111111111111111;

export const IdleHydrationLane: Lane = 0b0001000000000000000000000000000;

// 空闲时lane
export const IdleLane: Lane = 0b0010000000000000000000000000000;

export const OffscreenLane: Lane = 0b0100000000000000000000000000000;
export const DeferredLane: Lane = 0b1000000000000000000000000000000;

// 更新lanes
export const UpdateLanes: Lanes =
  SyncLane | InputContinuousLane | DefaultLane | TransitionLanes;

btw:Hydration(水合)是什么?

在 React 中,Hydration是指在服务器端渲染(SSR)的 React 应用中,将服务器生成的 HTML 与客户端上的 React 组件关联起来的过程。这一过程通常发生在浏览器加载了服务端渲染的 HTML 和客户端 JavaScript 代码之后。Hydration 确保了客户端应用能够接管服务器端渲染出的静态内容,并添加事件处理器以及其他需要浏览器 API 实现的交互性能力。

获取最高优先级的lane和lanes

既然lane是优先级模型,我们肯定需要能够获取最高优先级的lane和lanes,在lane模型中,数值越小优先级越高

获取最高优先级的lane

可以看到方法很简单,这就是位运算的优势了,其实这里取最高优先级的lane就是取lanes的最右位的值

export function getHighestPriorityLane(lanes: Lanes): Lane {
  return lanes & -lanes;
}

比如:

const lanes = 0b0000000000000000000000000011110
const notLanes = -lanes
const highestPriorityLane = lanes & notLanes 
// 2 (0b0000000000000000000000000000010)
最高优先级的lane就是0b0000000000000000000000000000010,对应的同步lane

获取最高优先级的lanes

和getHighestPriorityLane差不多,下一个

/** enableUnifiedSyncLane默认为true,所以SyncUpdateLanes默认为第一种结果,也就是
* 0b0000000000000000000000000101010
*/
export const SyncUpdateLanes: Lane = enableUnifiedSyncLane
  ? SyncLane | InputContinuousLane | DefaultLane
  : SyncLane;


function getHighestPriorityLanes(lanes: Lanes | Lane): Lanes {
  // enableUnifiedSyncLane默认为true,来自shared/ReactFeatureFlags
  if (enableUnifiedSyncLane) {
    const pendingSyncLanes = lanes & SyncUpdateLanes;
    // 如果当前lane有同步的情况,直接return
    if (pendingSyncLanes !== 0) {
      return pendingSyncLanes;
    }
  }
  // 从lanes中选出优先级最高的lane然后return
  switch (getHighestPriorityLane(lanes)) {
    case SyncHydrationLane:
      return SyncHydrationLane;
    case SyncLane:
      return SyncLane;
    case InputContinuousHydrationLane:
      return InputContinuousHydrationLane;
    case InputContinuousLane:
      return InputContinuousLane;
    case DefaultHydrationLane:
      return DefaultHydrationLane;
    case DefaultLane:
      return DefaultLane;
    case TransitionHydrationLane:
      return TransitionHydrationLane;
    case TransitionLane1:
    case TransitionLane2:
    case TransitionLane3:
    case TransitionLane4:
    case TransitionLane5:
    case TransitionLane6:
    case TransitionLane7:
    case TransitionLane8:
    case TransitionLane9:
    case TransitionLane10:
    case TransitionLane11:
    case TransitionLane12:
    case TransitionLane13:
    case TransitionLane14:
    case TransitionLane15:
      return lanes & TransitionLanes;
    case RetryLane1:
    case RetryLane2:
    case RetryLane3:
    case RetryLane4:
      return lanes & RetryLanes;
    case SelectiveHydrationLane:
      return SelectiveHydrationLane;
    case IdleHydrationLane:
      return IdleHydrationLane;
    case IdleLane:
      return IdleLane;
    case OffscreenLane:
      return OffscreenLane;
    case DeferredLane:
      return NoLanes;
    default:
      return lanes;
  }
}

获取FiberRoot的下一个需要调度的lanes

export function getNextLanes(root: FiberRoot, wipLanes: Lanes): Lanes {
  // root上待处理的lanes
  const pendingLanes = root.pendingLanes;
  // 如果为NoLanes直接return
  if (pendingLanes === NoLanes) {
    return NoLanes;
  }

  let nextLanes: Lanes = NoLanes;

  // root上挂起的lanes
  const suspendedLanes = root.suspendedLanes;
  // root上已经被标记的lanes
  const pingedLanes = root.pingedLanes;

  // 通过& NonIdleLanes过滤掉所有IdleLanes
  const nonIdlePendingLanes = pendingLanes & NonIdleLanes;
  // 先执行nonIdle的lane,IdleLane是在所有其他lane都执行完成之后才能执行
  if (nonIdlePendingLanes !== NoLanes) {
    // 通过& ~ 的位计算来排除suspendedLanes(挂起的Lanes)
    const nonIdleUnblockedLanes = nonIdlePendingLanes & ~suspendedLanes;
    if (nonIdleUnblockedLanes !== NoLanes) {
      // 从nonIdleUnblockedLanes中找到优先级最高的lane
      nextLanes = getHighestPriorityLanes(nonIdleUnblockedLanes);
    } else {
      // 如果排除挂起的之后为空,就从挂起的中找到优先级最高的lane
      const nonIdlePingedLanes = nonIdlePendingLanes & pingedLanes;
      if (nonIdlePingedLanes !== NoLanes) {
        nextLanes = getHighestPriorityLanes(nonIdlePingedLanes);
      }
    }
  } else {
    // 如果只有idleLanes就会走到这个逻辑,同样要排除suspendedLanes
    const unblockedLanes = pendingLanes & ~suspendedLanes;
    if (unblockedLanes !== NoLanes) {
      nextLanes = getHighestPriorityLanes(unblockedLanes);
    } else {
      if (pingedLanes !== NoLanes) {
        nextLanes = getHighestPriorityLanes(pingedLanes);
      }
    }
  }

  // 如果上述都找不到lanes,那就直接return
  if (nextLanes === NoLanes) {
    return NoLanes;
  }

  // 将wipLanes和我们找到nextLanes进行优先级的比较
  if (
    wipLanes !== NoLanes &&
    wipLanes !== nextLanes &&
    (wipLanes & suspendedLanes) === NoLanes
  ) {
    const nextLane = getHighestPriorityLane(nextLanes);
    const wipLane = getHighestPriorityLane(wipLanes);
    // 如果nextLane优先级比wipLane高 return wipLanes
    if (
      nextLane >= wipLane ||
      (nextLane === DefaultLane && (wipLane & TransitionLanes) !== NoLanes)
    ) {
      return wipLanes;
    }
  }
  return nextLanes;
}

一些lane的操作计算方法

// 是否有交集
export function includesSomeLane(a: Lanes | Lane, b: Lanes | Lane): boolean {
  return (a & b) !== NoLanes;
}

// 是否是子集
export function isSubsetOfLanes(set: Lanes, subset: Lanes | Lane): boolean {
  return (set & subset) === subset;
}

// 合并两个lane
export function mergeLanes(a: Lanes | Lane, b: Lanes | Lane): Lanes {
  return a | b;
}

// 排除某个lane
export function removeLanes(set: Lanes, subset: Lanes | Lane): Lanes {
  return set & ~subset;
}

// 两个lane相交
export function intersectLanes(a: Lanes | Lane, b: Lanes | Lane): Lanes {
  return a & b;
}

和scheduler中优先级的关联

react中是使用scheduler库对任务进行的调度,scheduler有自己的优先级,而lane就代表来react中任务的优先级,那么lane和scheduler中的优先级如何对应上呢,如下:

将lanes转换成事件优先级:

export const NoEventPriority: EventPriority = NoLane;
export const DiscreteEventPriority: EventPriority = SyncLane;
export const ContinuousEventPriority: EventPriority = InputContinuousLane;
export const DefaultEventPriority: EventPriority = DefaultLane;
export const IdleEventPriority: EventPriority = IdleLane;

// 优先级比较方法
export function isHigherEventPriority(
  a: EventPriority,
  b: EventPriority,
): boolean {
  return a !== 0 && a < b;
}

// 将lanes转换成事件优先级
export function lanesToEventPriority(lanes: Lanes): EventPriority {
  // 获取优先级最高的lane
  const lane = getHighestPriorityLane(lanes);
  // 如果lane优先级比DiscreteEventPriority高,则return DiscreteEventPriority
  if (!isHigherEventPriority(DiscreteEventPriority, lane)) {
    return DiscreteEventPriority;
  }
  // 其他同理
  if (!isHigherEventPriority(ContinuousEventPriority, lane)) {
    return ContinuousEventPriority;
  }
  if (includesNonIdleWork(lane)) {
    return DefaultEventPriority;
  }
  return IdleEventPriority;
}

根据转换的事件优先级得到schedulerPriorityLevel,然后进行调度:

import {
  ImmediatePriority as ImmediateSchedulerPriority,
  UserBlockingPriority as UserBlockingSchedulerPriority,
  NormalPriority as NormalSchedulerPriority,
  IdlePriority as IdleSchedulerPriority,
  cancelCallback as Scheduler_cancelCallback,
  scheduleCallback as Scheduler_scheduleCallback,
  now,
} from './Scheduler';

function scheduleTaskForRootDuringMicrotask(
  root: FiberRoot,
  currentTime: number,
): Lane {
  // ...
  let schedulerPriorityLevel;
  // 根据转换的事件优先级得到schedulerPriorityLevel
  switch (lanesToEventPriority(nextLanes)) {
    case DiscreteEventPriority:
      // DiscreteEventPriority对应ImmediateSchedulerPriority,值为1
      schedulerPriorityLevel = ImmediateSchedulerPriority;
      break;
    case ContinuousEventPriority:
      // ContinuousEventPriority对应UserBlockingSchedulerPriority,值为2
      schedulerPriorityLevel = UserBlockingSchedulerPriority;
      break;
    case DefaultEventPriority:
      // 其他同理
      schedulerPriorityLevel = NormalSchedulerPriority;
      break;
    case IdleEventPriority:
      schedulerPriorityLevel = IdleSchedulerPriority;
      break;
    default:
      schedulerPriorityLevel = NormalSchedulerPriority;
      break;
  }

  // 最后使用schedulerPriorityLevel进行任务调度
  const newCallbackNode = scheduleCallback(
    schedulerPriorityLevel,
    performConcurrentWorkOnRoot.bind(null, root),
  );
  root.callbackPriority = newCallbackPriority;
  root.callbackNode = newCallbackNode;
  return newCallbackPriority;
}
}