zoukankan      html  css  js  c++  java
  • 动画requestAnimationFrame

    前言

    在研究canvas的2D pixi.js库的时候,其动画的刷新都用requestAnimationFrame替代了setTimeout 或 setInterval

    但是jQuery中还是采用了setInterval,我这章就研究下顺便改造下jQuery的动画

    定时器

    jQuery动画的实现考虑到兼容与易用性采用了setInterval来不断绘制新的属性值,从而达到动画的效果。

    大部分浏览器的显示频率是16.7ms,由于浏览器的特性,setInterval会有一个丢帧的问题

    即使向其传递毫秒为单位的参数,它们也不能达到ms的准确性。这是因为javascript是单线程的,可能会发生阻塞

    jQuery会有一个全局设置jQuery.fx.interval = 13 设置动画每秒运行帧数。

    默认是13毫秒。该属性值越小,在速度较快的浏览器中(例如,Chrome),动画执行的越流畅,但是会影响程序的性能并且占用更多的 CPU 资源

    那么归纳一点最关键的问题:

    开发着并不知道下一刻绘制动画的最佳时机是什么时候

    requestAnimationFrame

    requestAnimationFrame 是专门为实现高性能的帧动画而设计的一个API

    说简单点

    • setInterval、setTimeout是开发者主动要求浏览器去绘制,但是由于种种问题,浏览器可能会漏掉部分命令
    • requestAnimationFrame 就是浏览器什么要开始绘制了浏览器自己知道,通过requestAnimationFrame 告诉开发者,这样就不会出现重复绘制丢失的问题了

    目前已在多个浏览器得到了支持,包括IE10+,Firefox,Chrome,Safari,Opera等,在移动设备上,ios6以上版本以及IE mobile 10以上也支持requestAnimationFrame,

    唯一比较遗憾的是目前安卓上的原生浏览器并不支持requestAnimationFrame,不过对requestAnimationFrame的支持应该是大势所趋了,安卓版本的chrome 16+也是支持requestAnimationFrame的。

    比较

    区别:

    1. requestAnimationFrame 会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率,一般来说,这个频率为每秒60帧
    2. 隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的的cpu,gpu和内存使用量。
    3. requestAnimationFrame也会像setTimeout一样有一个返回值ID用于取消,可以把它作为参数传入cancelAnimationFrame函数来取消requestAnimationFrame的回调

    兼容处理

    摘自HTML5 Canvas 核心技术

    window.requestNextAnimationFrame = (function () {
      var originalWebkitRequestAnimationFrame = undefined,
          wrapper = undefined,
          callback = undefined,
          geckoVersion = 0,
          userAgent = navigator.userAgent,
          index = 0,
          self = this;
    
      // Workaround for Chrome 10 bug where Chrome
      // does not pass the time to the animation function
    
      if (window.webkitRequestAnimationFrame) {
        // Define the wrapper
    
        wrapper = function (time) {
          if (time === undefined) {
            time = +new Date();
          }
          self.callback(time);
        };
    
        // Make the switch
    
        originalWebkitRequestAnimationFrame = window.webkitRequestAnimationFrame;
    
        window.webkitRequestAnimationFrame = function (callback, element) {
          self.callback = callback;
    
          // Browser calls the wrapper and wrapper calls the callback
    
          originalWebkitRequestAnimationFrame(wrapper, element);
        }
      }
    
      // Workaround for Gecko 2.0, which has a bug in
      // mozRequestAnimationFrame() that restricts animations
      // to 30-40 fps.
    
      if (window.mozRequestAnimationFrame) {
        // Check the Gecko version. Gecko is used by browsers
        // other than Firefox. Gecko 2.0 corresponds to
        // Firefox 4.0.
    
        index = userAgent.indexOf('rv:');
    
        if (userAgent.indexOf('Gecko') != -1) {
          geckoVersion = userAgent.substr(index + 3, 3);
    
          if (geckoVersion === '2.0') {
            // Forces the return statement to fall through
            // to the setTimeout() function.
    
            window.mozRequestAnimationFrame = undefined;
          }
        }
      }
    
      return  window.requestAnimationFrame ||
          window.webkitRequestAnimationFrame ||
          window.mozRequestAnimationFrame ||
          window.oRequestAnimationFrame ||
          window.msRequestAnimationFrame ||
    
          function (callback, element) {
            var start,
                finish;
    
            window.setTimeout(function () {
              start = +new Date();
              callback(start);
              finish = +new Date();
    
              self.timeout = 1000 / 60 - (finish - start);
    
            }, self.timeout);
          };
    }());
    
      window.cancelNextRequestAnimationFrame = window.cancelRequestAnimationFrame
        || window.webkitCancelAnimationFrame
        || window.webkitCancelRequestAnimationFrame
        || window.mozCancelRequestAnimationFrame
        || window.oCancelRequestAnimationFrame
        || window.msCancelRequestAnimationFrame
        || clearTimeout;

    对比

    通过requestAnimationFrame与setInterval同样的效果对比

    一段动画采用setInterval与requestAnimationFrame,分别给出了webKit下调用刷新的次数

    setInterval实现,调用了144次左右


    requestAnimationFrame 实现调用了120次左右


    通过对比,在同样的时间里,通过定时器刷新的次数是要更多,当然定时器跟设置的时间是有关系的

    这里我要强调一点,有效值,就是我们在浏览器能接受的范围内,给出一个最佳的渲染时间,这样才是一个性能优化的最佳的选择

  • 相关阅读:
    阶段性总结(PHP-JSON)
    阶段性总结(PHP-Array函数)
    JavaScript异步加载的三种方式——async和defer、动态创建script
    event.target 和 event.currentTarget 的区别
    面试题:常用的http状态码
    JS变量重复声明以及忽略var 声明的问题及其背后的原理
    line-height:1.5和line-height:150%的区别
    Web前端性能优化——如何提高页面加载速度
    Promise和setTimeout执行顺序 面试题
    过目不忘JS正则表达式
  • 原文地址:https://www.cnblogs.com/aaronjs/p/4283109.html
Copyright © 2011-2022 走看看