使用requestAnimationFrame减少浏览器重绘
文章目录
- 介绍
- 使用
- 使用rAM前
- 使用rAM后
介绍
- 在屏幕中,浏览器通常都以60FPS(1/60 s)每帧更新屏幕,但是当前端绑定了一些高频事件,如鼠标移动,屏幕滚动、触摸滑动等时,在一帧的周期内,事件会多次触发,但页面只刷新一次。这种情况就可能导致丢帧现象,抑或者回调函数处理时间过长,也会导致下一帧的重绘延迟,出现卡顿效果。
- 通过requestAnimationFrame(rAF)保证在一帧的周期内,函数只触发一次然后渲染,就能有效的降低卡顿。
使用
记录一个标志变量判断是否有正在进行的rAM,若有,停止触发绑定事件;否则将标志置为true,在rAM周期内执行回调函数,执行完成后将标志变量置为false
使用rAM前
绘制多边形用到了mapbox-gl-draw这个插件,原生用法参考mapbox-gl-draw示例,在mapbox在react是一般这样子使用:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>webgl</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style>
body {
margin: 0;
padding: 0;
}
#img1 {
width: 100px;
height: 100px;
background-image: url('./img/img1.jpg');
background-repeat: no-repeat;
background-size: 100% 100%;
}
#img2 {
width: 100px;
height: 100px;
background-image: url('./img/img2.jpg');
background-repeat: no-repeat;
background-size: 100% 100%;
}
#img3 {
width: 100px;
height: 100px;
background-image: url('./img/img1.jpg');
background-repeat: no-repeat;
background-size: 100% 100%;
}
</style>
</head>
<body>
<div id="main">
<div class="img" id="img1"> </div>
<div class="img" id="img2"> </div>
<div class="img" id="img2"> </div>
</div>
<script>
let imgDiv = document.getElementsByClassName('img')
let flag = false
// 重绘操作
function rePaint (pos) {
for(let i = 0; i<imgDiv.length; i++) {
imgDiv[i].style.width = (Math.sin(pos/1000) + Math.PI / 2) * 100 + 'px'
imgDiv[i].style.height = (Math.sin(pos/1000) + Math.PI / 2) * 100 + 'px'
}
}
// 高频触发函数,
window.addEventListener('pointermove',(e)=>{
rePaint(pos)
})
</script>
</body>
</html>
使用rAM后
绘制多边形用到了mapbox-gl-draw这个插件,原生用法参考mapbox-gl-draw示例,在mapbox在react是一般这样子使用:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>webgl</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style>
body {
margin: 0;
padding: 0;
}
#img1 {
width: 100px;
height: 100px;
background-image: url('./img/img1.jpg');
background-repeat: no-repeat;
background-size: 100% 100%;
}
#img2 {
width: 100px;
height: 100px;
background-image: url('./img/img2.jpg');
background-repeat: no-repeat;
background-size: 100% 100%;
}
#img3 {
width: 100px;
height: 100px;
background-image: url('./img/img1.jpg');
background-repeat: no-repeat;
background-size: 100% 100%;
}
</style>
</head>
<body>
<div id="main">
<div class="img" id="img1"> </div>
<div class="img" id="img2"> </div>
<div class="img" id="img2"> </div>
</div>
<script>
let imgDiv = document.getElementsByClassName('img')
let flag = false
// 重绘操作
function rePaint (pos) {
for(let i = 0; i<imgDiv.length; i++) {
imgDiv[i].style.width = (Math.sin(pos/1000) + Math.PI / 2) * 100 + 'px'
imgDiv[i].style.height = (Math.sin(pos/1000) + Math.PI / 2) * 100 + 'px'
}
}
// 高频触发函数,
window.addEventListener('pointermove',(e)=>{
let pos = e.clientX;
// 判断,如果有一个正在进行的rAM,停止继续触发;否则将flag置为true
if(flag) return;
flag = true;
window.requestAnimationFrame(()=>{
// 此帧执行结束后,将flag重新置为false
rePaint(pos)
flag = false;
})
})
</script>
</body>
</html>