requestAnimationFrame

requestAnimationFrame

采用系统时间间隔,保持最佳绘制效率,一般浏览器重绘频率为1000ms/60帧是16.7ms;所以一旦小于这个值,浏览器就会重复绘制消耗性能;

const timer = time=> console.log('animation called at', time)
// 这样就会在同一帧内绘制了两次动画
requestAnimationFrame(timer)
requestAnimationFrame(timer)

所以在一些高频绘制的场景比如scroll等,就会造成过度绘制的问题;

window.addEventListener('scroll', e => {
  requestAnimationFrame(time => {
    timer(time)
  })
})

解决方法:通过requestAnimationFrame来管理队列,其思路就是保证requestAnimationFrame的队列里,同样的回调函数只有一个;

let s = () => {
  let bool;
  if(bool) {return}
  bool = true;
  requestAnimationFrame(time => {
    bool = false;
    timer(time);
  })
}
window.addEventListener('scroll', s)

特点:

  1. requestAnimationFrame会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率;
  2. 在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的CPU、GPU和内存使用量;
  3. requestAnimationFrame是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停,有效节省了CPU开销;
  4. requestAnimationFrame返回一个整数,表示定时器的编号,这个值可以传递给cancelAnimationFrame用于取消这个函数的执行;
  5. cancelAnimationFrame可以取消绘制;
<html>
  <style>
    #myDiv{
      background: #abcdef;width: 0;height:2rem;line-height:2rem;
    }
  </style>
  <body>
    <div id='myDiv'>0%</div>
    <button id='btn'>btn</button>
    <script>
      var timer;
      btn.onclick=()=>{
        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>

requestIdleCallback

  • requestIdleCallback回调的执行的前提条件是当前浏览器处于空闲状态;
  • requestAnimationFrame的回调会在每一帧确定执行,属于高优先级任务,而requestIdleCallback的回调则不一定,属于低优先级任务;如果1帧内有空闲时间,就可以执行;如果浏览器一直繁忙,可以传入第二个参数{timeout: 2000}
  • requestIdleCallback回调中不推荐dom操作;
原文地址:https://www.cnblogs.com/colima/p/8471639.html