在 MDN 文档中,对 requestAnimationFrame 介绍是:告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。根据宏任务和微任务的定义,显然 requestAnimationFrame 属于宏任务。
1. 先说 raf 优点
1.1 提高性能和电池寿命
为了提高性能和电池寿命,因此在大多数浏览器里,当 requestAnimationFrame() 运行在后台标签页或者隐藏的<iframe> 里时,requestAnimationFrame() 会被暂停调用以提升性能和电池寿命。
1.2 raf 执行频率和系统保持一致
raf 的执行步伐跟着系统的绘制频率走,它能保证回调函数在屏幕每一次的绘制间隔中只被执行一次,这样就不会引起丢帧现象,也不会导致动画出现卡顿的问题。前提是保证浏览器的“绘制任务”没有被阻塞,另外回调函数本身没有耗时任务。
2. 使用 raf 也能写出很卡的动画
下面使用 raf 来做动画很卡,是因为 raf 的回调函数中有耗时长任务。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>requestAnimateFrame</title>
<style>
#box {
width: 100px;
height: 100px;
border: 1px solid red;
}
</style>
</head>
<body>
<div id="box"></div>
</body>
<script>
function nextTick(fn) {
window.requestAnimationFrame(fn);
}
function longTask() {
var sum
for (let i = 0; i < 10000000; i++) {
sum += i * Math.random();
}
return sum
}
var box = document.querySelector("#box");
var ml = 0;
function animate(timestamp) {
time = Date.now()
if (ml > 200) {
return
}
ml += 10;
longTask();
box.style.marginLeft = `${ml}px`;
nextTick(animate);
}
animate()
</script>
</html>
3. raf 的回调函数什么时候执行
从表现来看,raf 任务,也需要等宏任务执行之后完成之后,再执行。
function longTask() {
var s = Date.now();
var sum = 0;
for (let i = 0; i < 100000000; i++) {
sum += i;
}
console.log('longTask spend', Date.now() - s);
}
var t = Date.now()
window.requestAnimationFrame(function (timestamp) {
console.log('raf callback start', Date.now() - t)
console.log("timestamp", timestamp)
})
longTask()
// longTask spend 101
// raf callback start 102
// timestamp 8.685
4. raf 和 setTimeout (60帧) 本质区别
这里我抛出一个问题,如何写代码去验证两者的区别,如果你能写出代码来验证两者的明显区别,麻烦你在评论区留言。
setTimeout和setInterval的问题是,它们都不精确。它们的内在运行机制决定了时间间隔,参数实际上只是指定了把动画代码添加到浏览器UI线程队列中以等待执行的时间。如果队列前面已经加入了其他任务,那动画代码就要等前面的任务完成后再执行。
requestAnimationFrame 采用系统时间间隔,保持最佳绘制效率,不会因为间隔时间过短,造成过度绘制,增加开销;也不会因为间隔时间太长,使用动画卡顿不流畅,让各种网页动画效果能够有一个统一的刷新机制,从而节省系统资源,提高系统性能,改善视觉效果
4.1 raf
requestAnimationFrame 是专门为实现高性能的帧动画而设计的一个API
- setInterval、setTimeout 是开发者主动要求浏览器去绘制,但是由于种种问题,浏览器可能会漏掉部分命令
- requestAnimationFrame 就是浏览器什么要开始绘制了浏览器自己知道,通过requestAnimationFrame 告诉开发者,这样就不会出现重复绘制丢失的问题了
4.2 raf 和 setTimeout 区别
- requestAnimationFrame 会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率,一般来说,这个频率为每秒60帧
- 隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的的cpu,gpu和内存使用量。
网友评论