requestIAnimationframe
- CPU节能: 当页面处理未激活的状态下,该页面的屏幕刷新任务也会被系统暂停
- 减少dom操作: requestAnimationFrame会把每一帧中的所有 DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率,一般来说,这个频率为每秒 60 帧。
- 函数节流:在高频率事件( resize, scroll等)中,为了防止在一个刷新间隔内发生多次函数执行,RequestAnimationFrame可保证每个刷新间隔内,函数只被执行一次,这样既能保证流畅性,也能更好的节省函数执行的开销,一个刷新间隔内函数执行多次时没有意义的,因为多数显示器每16.7ms 刷新一次,多次绘制并不会在屏幕上体现出来。
setTimeout
执行动画的缺点:它通过设定间隔时间来不断改变图像位置,达到动画效果。但是容易出现卡顿、抖动的现象;原因是:
- settimeout 任务被放入异步队列,只有当主线程任务执行完后才会执行队列中的任务,因此实际执行时间总是比设定时间要晚;
- settimeout 的固定时间间隔不一定与屏幕刷新间隔时间相同,会引起丢帧。
requestAnimationFrame模拟定时器setInterval
//存放系统中的定时器id
let timerIdMap = {
num: 0
}
export const myInterval = (callback, interval) => {
// 每设置一次定时器,num++ 代表系统中有num个自定义的定时器
timerIdMap.num++
// 第 num 个定时器的id
let intervalId = 'id' + timerIdMap.num
timerIdMap[intervalId] = true
// 循环次数
let count = 0
let startTime = Date.now()
let loop = () => {
// 系统map中不存在这个id,就停止循环
if (!timerIdMap[intervalId]) {
return
}
if (Date.now() > startTime + interval * (count + 1)) {
count++
callback(count)
}
window.requestAnimationFrame(loop)
}
loop()
return intervalId
}
// 清空定时器,删除全局的定时器id map
export function clearMyInterval(intervalId) {
delete timerIdMap[intervalId]
}
参考:https://blog.youkuaiyun.com/qq_17335549/article/details/128089405