文章目录
setTimeout 、setInterval、requestAnimationFrame
面试题
- setTimeout(cb, 0)会立刻执行吗?
- settimeout定时的时间准确吗? 为什么不准确? 怎么解决?
- setTimeout和requestAnimation的区别
- requestAnimationFrame讲一下你的理解
- setTimeout实际延迟时间
- 用setTimeout实现setInterval,实现一个随时停止的版本
- setTimeout 和 setInterval区别
- JS实现动画的方式
- requestAnimationFrame与requestIdleCallback分别是什么?
- requestAnimationFrame的执行时机?
- 事件循环,宏任务微任务
- requestAnimationframe回调函数中进行大量计算,会阻塞页面的渲染吗
setTimeout定时器的时间准吗?
setTimeout的时间是指ms之后将回调函数放入宏队列中,当时间为0时,
- 在nodejs中
setTimeout(demo, 0) === setTimeout(demo, 1)
,最小是1ms - 在浏览器里面
setTimeout(demo, 0) === setTimeout(demo, 4)
,最小是4ms
在事件循环中,先执行完同步代码后,先需要执行微队列中任务,然后再到宏队列,所以定时器的事件是不准确的
setTimeout 和 setInterval
setTimeout(fn,time)
:在指定时间后执行一次回调函数
setInterval(fn,time)
:周期性地执行回调函数
setInterval存在的问题
1.某些间隔被跳过;
2.实际代码执行间隔 <= 设定的时间间隔
假设,某个onclick事件处理程序使用setInterval()设置了200ms间隔的定时器。如果事件处理程序花了300ms多一点时间完成,同时定时器代码也花了差不多的时间,就会同时出现跳过某间隔的情况
使用setTimeout构造轮询能保证每次轮询的间隔
setTimeout(function fn() {
// do something
setTimeout(fn, delay)
}, delay)
当一个定时器执行完毕后,才开启另一个定时器。
这样做的好处 ①在前一个定时器代码执行完之前,不会向队列插入新的定时器代码,确保不会有任何缺失的间隔。② 它可以保证在下一次定时器代码执行之前,至少要等待指定的间隔,避免了连续的运行。
用setTimeout实现setInterval,可以随时停止
function mySetTimeout(fn,delay){
let timer = null;
let interval = ()=>{
fn();
timer = setTimeout(interval,delay); //开启后续定时器,取消也是取消后续的
}
setTimeout(interval,delay); //第一次调用定时器
return {
cancel:()=>{
clearTimeout(timer);
}
}
}
const { cancel } = mySetTimeout(() => console.log(888),1000)
setTimeout(()=>{
cancel()
},4000)
requestAnimationFrame H5新增API
JS实现动画的方法
- setTimeout
- setInterval
- requestAnimationFrame
显示器的刷新频率是60Hz,浏览器也会尽量保持60Hz的刷新率运行,也就是16.7ms刷新一帧所以(60次/s)
requestAnimationFrame是什么?
requestAnimationFrame是H5新增的API类似于setTimeout ,告诉浏览器在重新渲染屏幕之前执行。主要用途是按帧对网页进行重绘。
requestAnimationFrame的基本思想就是与显示屏的刷新频率保持同步,利用这个刷新频率进行页面重绘。
setTimeout 和requestAnimationFrame 的区别
类型 | 回调函数执行的时机 | 是否在后台一直执行 | 丢帧现象 |
---|---|---|---|
setTimeout | 用户指定时间,放入宏队列中,最终执行的时间是不确定的 | √ | √ 由于执行时间的不确定性,setTimeout的执行步调可能和屏幕的刷新步调不一致,从而引起丢帧现象。 |
requestAnimationFrame | 由系统决定回调函数的执行时机,在下次重绘之前调用 | × 它会在页面出现的时候才会执行,一旦页面不处于浏览器的当前标签,就会自动停止刷新 原因:当页面处于未激活的状态下,该页面的屏幕刷新任务会被系统暂停 | × 在重绘之前调用不会丢帧 |
requestIdleCallback
浏览器一帧内需要完成如下六个步骤的任务
- 处理用户的交互
- JS 解析执行
- 帧开始。窗口尺寸变更,页面滚去等的处理
- requestAnimationFrame(rAF)
- 布局
- 绘制
与requestAnimationFrame的区别
requestAnimationFrame
在每次屏幕刷新的时候被调用,重新渲染屏幕之前requestIdleCallback
在每次屏幕刷新时,判断当前帧是否还有多余的时间(上述6个步骤执行完后也就是重新渲染屏幕之后),如果有,则会调用requestIdleCallback
的回调函数,
每隔1s输出
for(var i = 0; i < 6; i++) {
setTimeout(() => {
console.log(i)
},1000)
}
- 上述代码会输出什么
1s后同时输出6个6 - 如何优化让 0 - 1 - 2 - 3 - 4 - 5 每隔一秒输出一个
输出012345可以将var
改成let
每隔1s输出
实现1:增加输出间隔
for(let i = 0; i < 6; i++) {
setTimeout(() => {
console.log(i);
timer = null;
},1000*i)
}
实现2 利用await/async 等上一个定时器执行完毕后再执行下一个
async function fn (){
for(let i=0;i<6;i++){
//await会阻塞程序
let res = await fn1(i);
console.log(res);
}
}
function fn1(item){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(item)
},1000)})
}
fn();