资讯专栏INFORMATION COLUMN

你应该知道的requestIdleCallback

SunZhaopeng / 1306人阅读

摘要:因为回调的执行的前提条件是当前浏览器处于空闲状态。除了不推荐修改操作外,的操作也不建议放在里面,因为的回调会在的回调执行完成后立刻执行,会拉长当前帧的耗时,所以不推荐。推荐放在里面的应该是小块的并且可预测时间的任务。

我们都知道React 16实现了新的调度策略(Fiber), 新的调度策略提到的异步、可中断,其实就是基于浏览器的 requestIdleCallback和requestAnimationFrame两个API。所以这里我们有必要了解一下这两个API,关于Fiber部分后面会单开几篇讲。

什么是requestIdleCallback?

当关注用户体验,不希望因为一些不重要的任务(如统计上报)导致用户感觉到卡顿的话,就应该考虑使用requestIdleCallback。因为requestIdleCallback回调的执行的前提条件是当前浏览器处于空闲状态。

requestIdleCallback will schedule work when there is free time at the end of a frame, or when the user is inactive.

requestIdleCallback用法示例

    requestIdelCallback(myNonEssentialWork);
    
    
    function myNonEssentialWork (deadline) {
    
      // deadline.timeRemaining()可以获取到当前帧剩余时间
      while (deadline.timeRemaining() > 0 && tasks.length > 0) {
        doWorkIfNeeded();
      }
      if (tasks.length > 0){
        requestIdleCallback(myNonEssentialWork);
      }
    }
requestIdleCallback和requestAnimationFrame有什么区别?

requestAnimationFrame的回调会在每一帧确定执行,属于高优先级任务,而requestIdleCallback的回调则不一定,属于低优先级任务。
我们所看到的网页,都是浏览器一帧一帧绘制出来的,通常认为FPS为60的时候是比较流畅的,而FPS为个位数的时候就属于用户可以感知到的卡顿了,那么在一帧里面浏览器都要做哪些事情呢,如下所示:

图中一帧包含了用户的交互、js的执行、以及requestAnimationFrame的调用,布局计算以及页面的重绘等工作。
假如某一帧里面要执行的任务不多,在不到16ms(1000/60)的时间内就完成了上述任务的话,那么这一帧就会有一定的空闲时间,这段时间就恰好可以用来执行requestIdleCallback的回调,如下图所示:

由于requestIdleCallback利用的是帧的空闲时间,所以就有可能出现浏览器一直处于繁忙状态,导致回调一直无法执行,这其实也并不是我们期望的结果(如上报丢失),那么这种情况我们就需要在调用requestIdleCallback的时候传入第二个配置参数timeout了?

requestIdleCallback(myNonEssentialWork, { timeout: 2000 });

function myNonEssentialWork (deadline) {
  // 当回调函数是由于超时才得以执行的话,deadline.didTimeout为true
  while ((deadline.timeRemaining() > 0 || deadline.didTimeout) &&
         tasks.length > 0) {
       doWorkIfNeeded();
    }
  if (tasks.length > 0) {
    requestIdleCallback(myNonEssentialWork);
  }
}

如果是因为timeout回调才得以执行的话,其实用户就有可能会感觉到卡顿了,因为一帧的执行时间必然已经超过16ms了

requestIdleCallback里面可以执行DOM修改操作吗?

强烈建议不要,从上面一帧的构成里面可以看到,requestIdleCallback回调的执行说明前面的工作(包括样式变更以及布局计算)都已完成。如果我们在callback里面做DOM修改的话,之前所做的布局计算都会失效,而且如果下一帧里有获取布局(如getBoundingClientRect、clientWidth)等操作的话,浏览器就不得不执行强制重排工作,这会极大的影响性能,另外由于修改dom操作的时间是不可预测的,因此很容易超出当前帧空闲时间的阈值,故而不推荐这么做。推荐的做法是在requestAnimationFrame里面做dom的修改,可以在requestIdleCallback里面构建Document Fragment,然后在下一帧的requestAnimationFrame里面应用Fragment。

除了不推荐DOM修改操作外,Promise的resolve(reject)操作也不建议放在里面,因为Promise的回调会在idle的回调执行完成后立刻执行,会拉长当前帧的耗时,所以不推荐。

推荐放在requestIdleCallback里面的应该是小块的(microTask)并且可预测时间的任务。关于microTask推荐看这里

requestIdleCallback的兼容情况


推荐使用npm包request-idle-callback

参考资料

https://developers.google.com...
https://medium.com/@paul_iris...
https://juejin.im/entry/59082...
https://insights.thoughtworks...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/94379.html

相关文章

  • 「译」代码优化策略 — Idle Until Urgent

    摘要:我将这个策略称之为闲置直到紧急。请注意,在脚本执行时,它作为单个任务需要毫秒才能运行完成。很明显,解决方案是将这些代码分解为多个任务。原因如下推迟组件初始化仅在组件尚未渲染时才有用。这称为输入优先级。 showImg(https://img.alicdn.com/tfs/TB1u.rsepzqK1RjSZFzXXXjrpXa-1919-913.png); Idle Until Urge...

    Ashin 评论0 收藏0
  • Deep In React之浅谈 React Fiber 架构(一)

    摘要:在上面我们已经知道浏览器是一帧一帧执行的,在两个执行帧之间,主线程通常会有一小段空闲时间,可以在这个空闲期调用空闲期回调,执行一些任务。另外由于这些堆栈是可以自己控制的,所以可以加入并发或者错误边界等功能。 文章首发于个人博客 前言 2016 年都已经透露出来的概念,这都 9102 年了,我才开始写 Fiber 的文章,表示惭愧呀。不过现在好的是关于 Fiber 的资料已经很丰富了,...

    Jiavan 评论0 收藏0
  • 「React 16」为 Luy 实现 React Fiber 架构

    摘要:开始写代码构造函数讲了那么多的理论,大家一定是晕了,但是没办法,架构已经比之前的简单要复杂太多了,因此不可能指望一次性把的内容全部理解,需要反复多看。 前言 Facebook 的研发能力真是惊人, Fiber 架构给 React 带来了新视野的同时,将调度一词介绍给了前端,然而这个架构实在不好懂,比起以前的 Vdom 树,新的 Fiber 树就麻烦太多。 可以说,React 16 和 ...

    DevWiki 评论0 收藏0
  • React Fiber 架构理解

    摘要:架构理解引用原文是核心算法正在进行的重新实现。构建的过程就是的过程,通过来调度执行一组任务,每完成一个任务后回来看看有没有插队的更紧急的,把时间控制权交还给主线程,直到下一次回调再继续构建。 React Fiber 架构理解 引用原文:React Fiber ArchitectureReact Fiber is an ongoing reimplementation of Reacts...

    Berwin 评论0 收藏0
  • 2017前端技术预览(未完结,最后更新于1月13日)

    摘要:图离线情况下发送微信消息,等网络正常后微信会继续处理我们的消息。无论是在微信中还是手机短信,在没有信号时都不影响我们编辑发送短信,等网络恢复时会自动帮我们把之前编辑好的信息顺利递送出去。 (删掉了第一小段,因为和内容关系不大。。) 本来这该是个技术分享会的内容,参加完 Google Developer Day(GDD) 后想做个 AI Demo 来分享,奈何技术实力不够,害怕把大家带进...

    cnio 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<