【React源码解析】深入剖析Scheduler源码

Scheduler调度

React中,有一个单独的Scheduler库专门用于处理上面讨论的时间切片。

我们简单看一下Scheduler关键源码实现:

  1. 首先,在 packagegs/react-reconciler/src/ReactFiberWorkLoop.new.js 文件中:
// 循环更新 fiber 节点
function workLoopConcurrent() {
  while (workInProgress !== null && !shouldYield()) {
    // 更新单个 fiber 节点
    performUnitOfWork(workInProgress);
  }
}

在更新时,如果是Concurrent模式,低优先级更新会进入到workLoopConcurrent函数。该函数的作用就是遍历Fiber节点,创建Fiber树并标记哪些Fiber被更新了。performUnitOfWork表示的是对每个Fiber节点的处理操作,每次处理前都会执行shouldYield()方法,下面看一下shouldYield

  1. 其次,在 packages/scheduler/src/forks/Scheduler.js文件中:
export const frameYieldMs = 5;
let frameInterval = frameYieldMs;

function shouldYieldToHost() {
  const timeElapsed = getCurrentTime() - startTime;
  // 判断时间间隔是否小于 5ms
  if (timeElapsed < frameInterval) {
    return false;
  }
  ...
}

shouldYield()方法会去判断累计更新的时间是否超过5ms

  1. 最后,在 packages/scheduler/src/forks/Scheduler.js文件中:
let schedulePerformWorkUntilDeadline;
if (typeof localSetImmediate === 'function') {
  schedulePerformWorkUntilDeadline = () => {
    localSetImmediate(performWorkUntilDeadline);
  };
} else if (typeof MessageChannel !== 'undefined') {
  const channel = new MessageChannel();
  const port = channel.port2;
  channel.port1.onmessage = performWorkUntilDeadline;
  schedulePerformWorkUntilDeadline = () => {
    port.postMessage(null);
  };
} else {
  schedulePerformWorkUntilDeadline = () => {
    localSetTimeout(performWorkUntilDeadline, 0);
  };
}

如果超过了5ms,就会通过schedulePerformWorkUntilDeadline开启一个宏任务进行下一个更新。这里react做了兼容的处理,实际上是优先使用MessageChannel而不是setTimeout,这是因为在浏览器帧中MessageChannel更优先于setTimeout执行。

总的来说,Scheduler库的处理和前面讨论的时间切片类似。事实上,浏览器也正在做同样的Scheduler库做的事情:通过内置一个api——scheduler.postTask 来解决用户交互在某些情况下无法即时相应的问题,有兴趣的话可以看看相关内容。

最终,通过这种时间切片的方式,在浏览器下的performance面板中,会呈现出如下渲染过程:原本一个耗时的更新(如渲染10000li标签),被分割为一个个5ms的小更新:
image.png

到这里,我们已经清楚了如何让一个耗时的更新不去阻塞用户事件和渲染了。但是这只是有一个更新任务的情况,如果在React更新一半时,click事件进来,然后执行click事件回调,并且触发了新的更新,那么该如何处理共存的两个更新呢?如果click事件的更新过程中,又有其他的click事件触发更新呢?这就涉及到多个更新并存的情况,这也是我们接下来需要讨论的点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值