js中requestAnimationFrame
为什么要说它,源于在牛客中的一个选择题。我之前还从未接触过requestAnimationFrame,很是无语,所以去百度了一番,结果里面还真有大学问。
for(let i = 0; i < 5; i++){
requestAnimationFrame(() => console.log(i));
}
这里有个前提知识,就是计算机刷新频率一般是60HZ,所以换算一下大概16.7ms刷新一次
requestAnimationFrame是一个类似于setTimeout的接口,主要用途就是将DOM操作集中起来,在一帧(16.7ms)时间点去集中完成。从而提升流畅度,改善视觉效果。
结合一个例子去简单阐述一下,正好看到有位博主在写一个js中的无限循环动画,感觉用这个例子可以很清晰的描述出来。
使用setInterval来实现无限循环
<!doctype html>
<html lang="en">
<head>
<title>Document</title>
<style>
#e{
width: 100px;
height: 100px;
background: red;
position: absolute;
left: 0;
}
</style>
</head>
<body>
<div id="e"></div>
<script>
let target = document.getElementById("e");
let flag = true;
let left = 0;
function render() {
if(flag == true){
if(left>=100){
flag = false
}
target.style.left = ` ${left++}px`
}else{
if(left<=0){
flag = true
}
target.style.left = ` ${left--}px`
}
}
setInterval(function(){
render()
},1000/60)
</script>
</body>
</html>
使用requestAnimationFrame实现无限循环
<!doctype html>
<html lang="en">
<head>
<title>Document</title>
<style>
#e{
width: 100px;
height: 100px;
background: red;
position: absolute;
left: 0;
}
</style>
</head>
<body>
<div id="e"></div>
<script>
let target = document.getElementById("e");
let flag = true;
let left = 0;
function render() {
if(flag == true){
if(left>=100){
flag = false
}
target.style.left = ` ${left++}px`
}else{
if(left<=0){
flag = true
}
target.style.left = ` ${left--}px`
}
}
//requestAnimationFrame效果
(function animloop() {
render();
window.requestAnimationFrame(animloop);
})();
</script>
</body>
</html>
呃呃呃~原本想展现一下使用requestAnimationFrame很流畅的样子,但是录制出来的gif效果好像不怎么明显。
大家可以自行实现一番,看看效果。
流畅原因
这里说明一下为什么使用requestAnimationFrame之后就会很流畅,感觉这里也是一个重要的知识点。
- 如果用setInterval,则会在16.7ms之后进行执行(准确来说是放入异步队列),只有当主线程任务执行完后才会执行队列中的任务,因此实际执行时间总是比设定时间要晚。所以它并不是在16.7ms内执行了一次,可能会发生在16.7ms内执行多次,从而发生多次重排重绘事件,因此看上去就很卡顿。
- 如果使用requestAnimationFrame,则明确就是说在16.7ms内执行一次,并且在这段时间内完成重排重绘事件,所以就流程许多
回归正题
requestAnimationFrame虽然是异步函数,但是由于i是用let定义的,每一次循环都会生成一个块级作用域,保存当前的值。
如果换成var i = 0,则输出结果为 4 4 4 4