setTimeout和setInterval
我们在用js实现动画时,经常会用到setTimeout和setInterval函数,但实际上它们都不精确。因为setTimeout和setInterval函数只是将任务放进异步队列中,只有当主线程上的任务执行完以后,才会去检查该队列里的任务是否需要开始执行,因此setTimeout和setInterval的实际执行时间,一般要比其设定的时间晚一些。
requestAnimationFrame
requestAnimationFrame的优势是:
CPU节能
使用setTimeout实现的动画,当页面被隐藏或最小化时,setTimeout 仍然在后台执行动画任务,由于此时页面处于不可见或不可用状态,刷新动画是没有意义的,完全是浪费CPU资源。而requestAnimationFrame则完全不同,当页面处理未激活的状态下,该页面的屏幕刷新任务也会被系统暂停,因此跟着系统步伐走的requestAnimationFrame也会停止渲染,当页面被激活时,动画就从上次停留的地方继续执行,有效节省了CPU开销。
函数节流
在高频率事件(resize,scroll等)中,为了防止在一个刷新间隔内发生多次函数执行,使用requestAnimationFrame可保证每个刷新间隔内,函数只被执行一次,这样既能保证流畅性,也能更好的节省函数执行的开销。一个刷新间隔内函数执行多次时没有意义的,因为显示器每16.7ms刷新一次,多次绘制并不会在屏幕上体现出来。
实例
requestAnimationFrame的用法比较简单,跟setTimeout基本一样。
1、无卡滞渲染十万条数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<ul>
</ul>
</body>
</html>
<script>
const total = 100000;//数据条数
const once = 20;//一次插入条数
const loopNum = Math.ceil(total/once);//循环数
let countRender = 0;//渲染次数
const ul = document.querySelector('ul');
function addItem(){
const fragment = document.createDocumentFragment();
for(let i=0;i<once;i++){
const li = document.createElement('li');
li.innerHTML =`第${countRender}批数据:::id==>${i}`;
fragment.appendChild(li);//这里不消耗dom性能
}
ul.appendChild(fragment);//20次添加,其实只消耗1次dom性能
countRender++;
console.log(countRender);
}
var timer = window.requestAnimationFrame(function fn(){
if(countRender < loopNum) {
addItem();
timer = window.requestAnimationFrame(fn); // 递归
}else{
cancelAnimationFrame(timer);
}
});
</script>
2、进度条效果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="myDiv" style="background-color: lightblue;width: 0;height: 20px;line-height: 20px;">0%</div>
<button id="btn">run</button>
<script>
var timer;
btn.onclick = function () {
myDiv.style.width = '0';
cancelAnimationFrame(timer);
timer = requestAnimationFrame(function fn() {
if (parseInt(myDiv.style.width) < 500) {
myDiv.style.width = parseInt(myDiv.style.width) + 5 + 'px';
myDiv.innerHTML = parseInt(myDiv.style.width) / 5 + '%';
timer = requestAnimationFrame(fn);
} else {
cancelAnimationFrame(timer);
}
});
}
</script>
</body>
</html>
参考文章:
https://blog.csdn.net/vhwfr2u02q/article/details/79492303
网友评论