面试题
setTimeout的时间是指ms之后将回调函数放入宏队列中,当时间为0时,
setTimeout(demo, 0) === setTimeout(demo, 1),最小是1mssetTimeout(demo, 0) === setTimeout(demo, 4),最小是4mssetTimeout(fn,time):在指定时间后执行一次回调函数
setInterval(fn,time):周期性地执行回调函数
setInterval存在的问题
1.某些间隔被跳过;
2.实际代码执行间隔 <= 设定的时间间隔
假设,某个onclick事件处理程序使用setInterval()设置了200ms间隔的定时器。如果事件处理程序花了300ms多一点时间完成,同时定时器代码也花了差不多的时间,就会同时出现跳过某间隔的情况
使用setTimeout构造轮询能保证每次轮询的间隔
setTimeout(function fn() {
// do something
setTimeout(fn, delay)
}, delay)
当一个定时器执行完毕后,才开启另一个定时器。
这样做的好处 ①在前一个定时器代码执行完之前,不会向队列插入新的定时器代码,确保不会有任何缺失的间隔。② 它可以保证在下一次定时器代码执行之前,至少要等待指定的间隔,避免了连续的运行。
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)
JS实现动画的方法
显示器的刷新频率是60Hz,浏览器也会尽量保持60Hz的刷新率运行,也就是16.7ms刷新一帧所以(60次/s)
requestAnimationFrame是什么?
requestAnimationFrame是H5新增的API类似于setTimeout ,告诉浏览器希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数。主要用途是按帧对网页进行重绘。
requestAnimationFrame的基本思想就是与显示屏的刷新频率保持同步,利用这个刷新频率进行页面重绘。
| 类型 | 回调函数执行的时机 | 是否在后台一直执行 | 丢帧现象 |
|---|---|---|---|
| setTimeout | 用户指定时间,放入宏队列中,最终执行的时间是不确定的 | √ | √ 由于执行时间的不确定性,setTimeout的执行步调可能和屏幕的刷新步调不一致,从而引起丢帧现象。 |
| requestAnimationFrame | 由系统决定回调函数的执行时机,在下次重绘之前调用 | × 它会在页面出现的时候才会执行,一旦页面不处于浏览器的当前标签,就会自动停止刷新 原因:当页面处于未激活的状态下,该页面的屏幕刷新任务会被系统暂停 | × 在重绘之前调用不会丢帧 |
浏览器一帧内需要完成如下六个步骤的任务
处理用户的交互
JS 解析执行
帧开始。窗口尺寸变更,页面滚去等的处理
requestAnimationFrame(rAF)
布局
绘制
requestAnimationFrame在每次屏幕刷新的时候被调用
requestIdleCallback在每次屏幕刷新时,判断当前帧是否还有多余的时间(上述6个步骤执行完后),如果有,则会调用requestIdleCallback的回调函数,
for(var i = 0; i < 6; i++) {
setTimeout(() => {
console.log(i)
},1000)
}
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++){
let res = await fn1(i);
console.log(res);
}
}
function fn1(item){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(item)
},1000)})
}
fn();