React中的高优先级任务插队机制

说到高优先级任务插队机制,就要提到Reat fiber这个东西了,也就是时间分片,说实话这东西我之前了解过,但是下午被面试官问到了,我还说都能答上来,结果突然问到时间分片后,被分化的小任务的执行顺序,还有就是如果有优先级高的任务插入进来,它们的执行顺序是什么,当时头皮发麻,想着我都说到这里了,怎么还问,刚刚看了下,其实原理很简单,下面一起来看看吧!

  在React的concurrent模式下,低优先级任务执行过程中,一旦有更高优先级的任务进来,那么这个低优先级的任务会被取消,优先执行高优先级任务。等高优先级任务做完了,低优先级任务会被重新做一遍。

我们用一个具体的例子来理解一下高优先级任务插队。

有这样一个组件,state为0,进入页面,会调用setState将state加1,这个作为低优先级任务。React开始进行更新,在这个低优先级任务尚未完成时,模拟按钮点击,state加2,这个作为高优先级任务。可以看到,页面上的数字变化为0 -> 2 -> 3,而不是0 -> 1 -> 3。这就说明,当低优先级任务(加1)正在进行时,高优先级任务进来了,而它会把state设置为2。由于高优先级任务的插队,设置state为1的低优先级任务会被取消,先做高优先级任务,所以数字从0变成了2。而高优先级任务完成之后,低优先级任务会被重做,所以state再从2加到了3。

现象如下:

任务插队

利用chrome的性能分析工具捕捉更新过程,可以明显看到优先级插队的过程 高优先级插队

完整的profile文件我保存下来了,可以载入到chrome中详细查看:高优先级插队.json

可以再看一下这个过程中两个任务优先级在调度过程中的信息

点击查看 高优先级插队示例代码文件。

点击查看 低优先级任务饥饿问题示例代码文件。

接下来我们就来从setState开始,探讨一下这种插队行为的本质,内容涉及update对象的生成、发起调度、工作循环、高优任务插队、update对象的处理、低优先级任务重做等内容。

产生更新

当调用setState时,意味着组件对应的fiber节点产生了一个更新。setState实际上是生成一个update对象,调用enqueueSetState,将这个update对象连接到fiber节点的updateQueue链表中.

Component.prototype.setState = function(partialState, callback) {
  this.updater.enqueueSetState(this, partialState, callback, 'setState');
};

复制代码 

enqueueSetState的职责是创建update对象,将它入队fiber节点的update链表(updateQueue),然后发起调度。

 enqueueSetState(inst, payload, callback) {
    // 获取当前触发更新的fiber节点。inst是组件实例
    const fiber = getInstance(inst);
    // eventTime是当前触发更新的时间戳
    const eventTime = requestEventTime();
    const suspenseConfig = requestCurrentSuspenseConfig();

    // 获取本次update的优先级
    const lane = requestUpdateLane(fiber, suspenseConfig);

    // 创建update对象
    const update = createUpdate(eventTime, lane, suspenseConfig);

    // payload就是setState的参数,回调函数或者是对象的形式。
    // 处理更新时参与计算新状态的过程
    update.payload = payload;

    // 将update放入fiber的updateQueue
    enqueueUpdate(fiber, update);

    // 开始进行调度
    scheduleUpdateOnFiber(fiber, lane, eventTime);
  }
复制代码 

梳理一下enqueueSetState中具体做的事情:

找到fiber

首先获取产生更新的组件所对应的fiber节点,因为产生的update对象需要放到fiber节点的updateQueue上。然后获取当前这个update产生的时间,这与更新的饥饿问题相关,我们暂且不考虑,而且下一步的suspenseConfig可以先忽略。

计算优先级

之后比较重要的是计算当前这个更新它的优先级lane:

const lane = requestUpdateLane(fiber, suspenseConfig);
复制代码 

计算这个优先级的时候,是如何决定根据什么东西去计算呢?这还得从React的合成事件说起。

事件触发时,合成事件机制调用scheduler中的runWithPriority函数,目的是以该交互事件对应的事件优先级去派发真正的事件流程。runWithPriority会将事件优先级转化为scheduler内部的优先级并记录下来。当调用requestUpdateLane计算lane的时候,会去获取scheduler中的优先级,以此作为lane计算的依据。

这部分的源码在这里

创建update对象, 入队updateQueue

根据lane和eventTime还有suspenseConfig,去创建一个update对象,结构如下:

const update: Update<*> = {
  eventTime,
  lane,
  suspenseConfig,
  tag: UpdateState,
  payload: n
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值