对于高频连续执行任务(如动画等),怎么处理呢?
setInterval
console.log('begin', Date.parse(new Date()))
function step() {
console.log('setInterval', Date.parse(new Date()))
start++;
element.style.left = (parseInt(element.style.left.slice(0, -2)) + 1) + 'px';
if (start > 200) {
clearInterval(timer)
}
}
let timer = setInterval(step, 10)
假如同时插入了其它任务:
console.log('begin', Date.parse(new Date()))
setTimeout(() => console.log('setTimeout1', Date.parse(new Date())), 1000)
for (let i = 0; i < 100000; i++) {
setTimeout(() => console.log('setTimeout', Date.parse(new Date())), 1)
}
会发现定时器是不准确的:
image.png
requestIdleCallback
React Fiber中的任务调度与此API息息相关
它调用函数时会给函数传两个参数:
- timeRemaining(): 当前帧还剩下多少时间
- didTimeout: 是否超时
它的作用是是在浏览器一帧的剩余空闲时间内执行任务,
即,在一帧结束前且没有别的高优先级任务的情况下,再执行该任务,
也就是说,requestIdleCallback的优先级低.
页面是一帧一帧绘制出来的,当每秒绘制的帧数(FPS)达到 60 时,页面是流畅的,小于这个值时,用户会感觉到卡顿。
1s 60帧,所以每一帧分到的时间是 1000/60 ≈ 16 ms。
示例:
function step(timestamp) {
start++;
element.style.left = (parseInt(element.style.left.slice(0, -2)) + 1) + 'px';
if (start < 200) {
console.log('requestIdleCallback', Date.parse(new Date()))
window.requestIdleCallback(step)
}
}
step()
console.log('begin', Date.parse(new Date()))
for (let i = 0; i < 100000; i++) {
setTimeout(() => console.log('setTimeout', Date.parse(new Date())), 1)
}
结果
image2.png
所有的requestIdleCallback都在主线程任务完成之后进行。
requestAnimationFrame
它的定义就是在浏览器下次绘制之前将会执行这个方法的回调。
即,每次绘制前都会优先执行requestAnimationFrame的任务
也就是说requestAnimationFrame的优先级高
它调用时给函数传一个参数:
- 一个 long 整数,请求 ID ,是回调列表中唯一的标识。是个非零值,没别的意义。
示例:
function step() {
start++;
element.style.left = (parseInt(element.style.left.slice(0, -2)) + 1) + 'px';
if (start < 200) {
console.log('requestAnimationFrame', Date.parse(new Date()))
window.requestAnimationFrame(step);
}
}
window.requestAnimationFrame(step);
console.log('begin', Date.parse(new Date()))
for (let i = 0; i < 100000; i++) {
setTimeout(() => console.log('setTimeout', Date.parse(new Date())), 1)
}
执行的结果:
image3.png
网友评论