React源码分析8-状态更新的优先级机制

为什么需要优先级

优先级机制最终目的是为了实现高优先级任务优先执行,低优先级任务延后执行

实现这一目的的本质就是在低优先级任务执行时,有更高优先级任务进来的话,可以打断低优先级任务的执行。

同步模式下的react运行时

我们知道在同步模式下,从 setState 到 虚拟DOM遍历,再到真实DOM更新,整个过程都是同步执行且无法被中断的,这样可能就会出现一个问题 —— 用户事件触发的更新被阻塞。

什么是用户事件触发的更新被阻塞?如果 React 正在进行更新任务,此时用户触发了交互事件,且在事件回调中执行了 setState,在同步模式下,这个更新任务需要 等待 当前正在更新的任务完成之后,才会被执行。假如当前 React 正在进行的更新任务耗时比较久,用户事件触发的更新任务不能及时被执行,造成下个更新任务被阻塞,从而形成了卡顿。

这时候,我们就希望能够及时响应用户触发的事件,优先执行用户事件触发的更新任务,也就是我们说的异步模式

我们可以比较一下,同步模式下和异步模式(优先级机制)下更新任务执行的差异

import React from "react";
import "./styles.css";

export default class extends React.Component {
  constructor() {
    super();
    this.state = {
      list: new Array(10000).fill(1),
    };
    this.domRef = null;
  }
  componentDidMount() {
    setTimeout(() => {
      console.log("setTimeout 准备更新", performance.now());
      this.setState(
        {
          list: new Array(10000).fill(Math.random() * 10000),
          updateLanes: 16
        },
        () => {
          console.log("setTimeout 更新完毕", performance.now());
        }
      );
    }, 100);
    setTimeout(() => {
      this.domRef.click();
    }, 150);
  }

  render() {
    const { list } = this.state;
    return (
      <div
        ref={(v) => (this.domRef = v)}        className="App"        onClick={() => {          console.log("click 准备更新", performance.now());          this.setState(            { list: new Array(10000).fill(2), updateLanes: 1 },            () => {              console.log("click 更新完毕", performance.now());            }          );        }}      >        {list.map((i, index) => (          <h1 key={i + +index}>Hello {i}</h1>
        ))}      </div>
    );
  }
}


click事件 触发的更新,会比 setTimeout 触发的更新更优先执行,做到了及时响应用户事件,打断 setTimeout 更新任务(低优先级任务)的执行。

如何运用优先级机制优化react运行时

为了解决同步模式渲染下的缺陷,我们希望能够对 react 做出下面这些优化

  1. 确定不同场景下所触发更新的优先级,以便我们可以决定优先执行哪些任务
  2. 若有更高优先级的任务进来,我们需要打断当前进行的任务,然后执行这个高优先级任务
  3. 确保低优先级任务不会被一直打断,在一定时间后能够被升级为最高优先级的任务

确定不同场景下的调度优先级

看过 react 源码的小伙伴可能都会有一个疑惑,为什么源码里面有那么多优先级相关的单词??怎么区分他们呢?

其实在 react 中主要分为两类优先级,scheduler 优先级和 lane 优先级,lane优先级下面又派生出 event 优先级

  • lane 优先级:主要用于任务调度前,对当前正在进行的任务和被调度任务做一个优先级校验,判断是否需要打断当前正在进行的任务
  • event 优先级:本质上也是lane优先级,lane优先级是通用的,event优先级更多是结合浏览器原生事件,对lane优先级做了分类和映射
  • scheduler 优先级:主要用在时间分片中任务过期时间的计算

lane优先级

可以用赛道的概念去理解lane优先级,lane优先级有31个,我们可以用31位的二进制值去表示,值的每一位代表一条赛道对应一个lane优先级,赛道位置越靠前,优先级越高

优先级 十进制值 二进制值 赛道位置
NoLane 0 0000000000000000000000000000000 0
SyncLane 1 0000000000000000000000000000001 0
InputContinuousHydrationLane 2 0000000000000000000000000000010 1
InputContinuousLane 4 0000000000000000000000000000100 2
DefaultHydrationLane 8 0000000000000000000000000001000 3
DefaultLane 16 0000000000000000000000000010000 4
TransitionHydrationLane 32 0000000000000000000000000100000 5
TransitionLane1 64 0000000000000000000000001000000 6
TransitionLane2 128 0000000000000000000000010000000 7
TransitionLane3 256 0000000000000000000000100000000 8
TransitionLane4 512 0000000000000000000001000000000 9
TransitionLane5 1024 0000000000000000000010000000000 10
TransitionLane 2048 0000000000000000000100000000000 11
TransitionLane7 4096 0000000000000000001000000000000 12
TransitionLane8 8192 0000000000000000010000000000000 13
TransitionLane9 16384 0000000000000000100000000000000 14
TransitionLane10 32768 0000000000000001000000000000000 15
TransitionLane11 65536 0000000000000010000000000000000 16
TransitionLane12 131072 0000000000000100000000000000000 17
TransitionLane13 262144 0000000000001000000000000000000 18
TransitionLane14 524288 0000000000010000000000000000000 19
TransitionLane15 1048576 0000000000100000000000000000000 20
TransitionLane16 2097152 0000000001000000000000000000000 21
RetryLane1 4194304 0000000010000000000000000000000 22
RetryLane2 8388608 0000000100000000000000000000000 23
RetryLane3 16777216 0000001000000000000000000000000 24
RetryLane4 33554432 0000010000000000000000000000000 25
RetryLane5 67108864 0000100000000000000000000000000 26
SelectiveHydrationLane 134217728 0001000000000000000000000000000 27
IdleHydrationLane 268435456 0010000000000000000000000000000 28
IdleLane 536870912 0100000000000000000000000000000 29
OffscreenLane 1073741824 1000000000000000000000000000000 30

event优先级

EventPriority Lane 数值
DiscreteEventPriority 离散事件。click、keydown、focusin等,事件的触发不是连续,可以做到快速响应 SyncLane 1
ContinuousEventPriority 连续事件。drag、scroll、mouseover等,事件的是连续触发的,快速响应可能会阻塞渲染,优先级较离散事件低 InputContinuousLane 4
DefaultEventPriority 默认的事件优先级 DefaultLane 16
IdleEventPriority 空闲的优先级 IdleLane 536870912

scheduler优先级

SchedulerPriority EventPriority 大于>17.0.2 小于>17.0.2
ImmediatePriority DiscreteEventPriority 1 99
UserblockingPriority Userblocking 2 98
NormalPriority Default
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值