前言
在网页中,有许多耗时但是却又不能那么紧要的任务。它们和紧要的任务,比如对用户的输入作出及时响应的之类的任务,它们共享事件队列。如果两者发生冲突,用户体验会很糟糕。我们可以使用setTimout,对这些任务进行延迟处理。但是我们并不知道,setTimeout在执行回调时,是否是浏览器空闲的时候。而requestIdleCallback就解决了这个痛点,requestIdleCallback会在帧结束时并且有空闲时间,或者用户不与网页交互时,执行回调。
帧渲染过程
在每一帧的渲染过程当中都会有一个空闲时间段,将我们的耗时任务插入其中来进行处理,不会影响之前的渲染进度,从而达到流畅度的提升。帧时间的计算方式是1000ms/刷新率 = 一帧的时间。比如1000ms/60hz 约等于16.6左右。
应用场景
requestIdleCallback实现页面快速响应 实例代码:
let b = document.getElementById("move")
let c = document.getElementById("c")
let begin = 1000
let width=100
function move(){
begin=100000
while(begin>=0){
console.log(1)
begin--
}
}
b.addEventListener("click",()=>{
move()//如果我们直接执行的话,浏览器会卡住,move方法是通过主线程进行的渲染的
//requestIdleCallback(move) //当我们用这个方法执行的时候,此时卡顿效果就会明显的减弱。
c.style.width=width+100+"px"
width++
})
再来一个例子感受一下requestIdleCallback的威力
let c = document.getElementById("c")
//睡眠方法
function delay(d){
let t=Date.now()
for(let i=Date.now();Date.now()-i<=d;){}
}
//任务列表
let works=[
()=>{
delay(20)
console.log(1,"being")
c.innerHTML="1"
c.style.width="200px"
console.log(1,"end")
},
()=>{
console.log(2,"being")
c.innerHTML="2"
c.style.width="300px"
delay(20)
console.log(2,"end")
},
()=>{
console.log(3,"being")
c.innerHTML="3"
c.style.width="100px"
delay(20)
console.log(3,"end")
}
]
//调度方法
function dod(deadline){
while(deadline.timeRemaining()>0&&works.length>0){
let work= works.shift()
work()
}
if(works.length>0){
maindo()
requestIdleCallback(dod)
}
}
function maindo(){
console.log("领导来了,先处理")
}
//开始执行
requestIdleCallback(dod)
假设一个场景 我们有一些列的子任务需要处理,但是又不能来阻塞主线程的任务,但是又要尽快执行子任务,此时就可用这个方式来执行了,虽然promise也可以做到,是根据js事件队列的处理模型来看,又无法满足我们的要求(当微任务过多的时候就会又长时间的延迟)
函数使用说明
//var handle = window.requestIdleCallback(callback[, options])
requestIdleCallback(myNonEssentialWork, { timeout: 2000 });
-
callback:回调,即空闲时需要执行的任务,该回调函数接收一个
IdleDeadline对象作为入参。其中IdleDeadline对象包含:didTimeout,布尔值,表示任务是否超时,结合timeRemaining使用。timeRemaining(),表示当前帧剩余的时间,也可理解为留给任务的时间还有多少。
-
options:目前 options 只有一个参数
timeout。表示超过这个时间后,如果任务还没执行,则强制执行,不必等待空闲。