js API-requestIdleCallback

js API之requestIdleCallback

什么是requestIdleCallback

window.requestIdleCallback() 方法插入一个函数,这个函数将在浏览器空闲时期被调用。这使开发者能够在主事件循环上执行后台和低优先级工作,而不会影响延迟关键事件,如动画和输入响应。函数一般会按先进先调用的顺序执行,然而,如果回调函数指定了执行超时时间timeout,则有可能为了在超时前执行函数而打乱执行顺序。

你可以在空闲回调函数中调用 requestIdleCallback(),以便在下一次通过事件循环之前调度另一个回调。

以上是MDN对requestIdleCallback的解释,那我们来细说一下这个api他的实际应用和用法。

触发时机

MDN对requestIdleCallback的解释中说到当浏览器空闲的时候函数会被调用,那什么是浏览器的空闲时间呢?

第一种出发条件

首先我们要知道FPS:通俗的来讲就是指画面的刷新率,其实无论游戏、电影、电视等视觉画面都是一张张连续变化的图片快速替换构成。60FPS就是1秒钟替换60次图片,达到60FPS人眼看起来是很流畅、连贯的画面了,所以普通显示器的刷新率就是60FPS。
我们以60FPS为例:
1s = 1000ms (1s等于1000毫秒)
1000 / 60 = 16.6666666 (一帧所用的时间大概就是 16.6ms)
在这一帧当中浏览器做了很多事情

  1. 处理用户事件,例如:click、input change等。
  2. 执行定时任务。
  3. 执行requestAnimationFrame
  4. 执行dom的回流与重绘
  5. 计算更新图层的绘制指令
  6. 绘制指令合并主线程若有空余时间会执行requestIdleCallback

一边情况下requestIdleCallback进入到上述情况下会很少,毕竟浏览器在一帧内执行了很多事情,所以更多情况下会在一下情况下触发

第二种触发条件

没有任务执行浏览器会有50ms空闲时间,这个时间段也会执行requestIdleCallback,大部分都是这个条件下去触发的。

requestIdleCallback(funciton(deadline){
	console.log(deadline.timeRemaining())
})

我们可以使用以上方法去测试它调用的时机,我们创建一个index.html,加入这段代码,你会发现这段代码会被console.log 稳定在16.6以内,说明是第一种方式调用。细心的你这里就会问了,你不是是说常常都是第二种方式触发么?秋豆马跌,这是因为我们index.html中什么业务逻辑也没有导致,想象如果把它放到我们的实际业务中去那肯定是第二种方式触发。
其实我们也可以测试,直接把这段代码放到控制台运行一下试试,你会发现console出了49.9 不超过50

这个东西你会发现和react的fiber有很大的联系,react是模仿requestIdleCallback的执行机制去实现了一个自己的api。react之所以不直接使用requestIdleCallback是因为react在调研requestIdleCallback的时候发现有概率出现20ms执行,超出了16.6ms这样的话我们看起来的动画就会卡顿。

React是如何实现的requestIdleCallback的呢?

  • React16 使用的是postMessage + requestAnimationFrame 实现了requestIdleCallback的polyfill。
    那为什么使用postMessage而不用setTimeout呢?是因为setTimeout 0是4ms,还是有延迟的,postMessage无延迟。
  • React 18 使用MessageChannel 实现了requestIdleCallback的polyfill
// 起初这个api是用于iframe通讯和window.open通讯。
let {port1, port2} = new MessageChannel();
// port1可以给port2发消息,2也可以给1发
// onmessage会隐性的开启 port1.start(),正常来说需要先start()
port1.onmessage = function(e){
	// e是MessageChannel的实例
	console.log('收到了来自port2的消息', e)
}
port2.onmessage = function(e){
	// e是MessageChannel的实例
	console.log('收到了来自port1的消息', e)
}
port1.postMessage('我是port1');
port2.postMessage('我是port2')

总结

我们项目中如果需要处理一些预加载资源的时候可以使用这个api,好多三方的库在做预加载的时候都会去使用requestIdleCallback。比如微前端中我们经常使用的无界,他的懒加载模块实现原理就是使用了requestIdleCallback API。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值