动画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次左右

    

    <!doctype html><img id="book" style="background:red;opacity:1;position: relative; left: 500px;" width="100" height="123" data-mce-style="background: red; opacity: 1; position: relative; left: 500px;" /><div id="several"><br /></div><script type="text/javascript">

    var book = document.getElementById(‘book‘)
    var several = document.getElementById(‘several‘);

    animate(book, {
    left: 50,
    duration: 2000
    })

    function animate(elem, options){
    //动画初始值
    var start = 500
    //动画结束值
    var end = options.left
    //动画id
    var timerId;
    var createTime = function(){
    return (+new Date)
    }
    //动画开始时间
    var startTime = createTime();

    var i = 0;

    function tick(){
    i++;
    several.innerHTML = ‘setInterval调用次数:‘ + i;
    //每次变化的时间
    var remaining = Math.max(0, startTime + options.duration - createTime())
    var temp = remaining / options.duration || 0;
    var percent = 1 - temp;
    var stop = function(){
    //停止动画
    clearInterval(timerId);
    timerId = null;
    }
    var setStyle = function(value){
    elem.style[‘left‘] = value + ‘px‘
    }
    //移动的距离
    var now = (end - start) * percent + start;
    if(percent === 1){
    setStyle(now)
    stop();
    }else{
    setStyle(now)
    }
    }

    //开始执行动画
    var timerId = setInterval(tick, 13);
    }
    </script>

    requestAnimationFrame 实现调用了120次左右

    

    <!doctype html><img id="book" style="background:red;opacity:1;position: relative; left: 500px;" width="100" height="123" data-mce-style="background: red; opacity: 1; position: relative; left: 500px;" /><div id="several"><br /></div><script type="text/javascript">

    var book = document.getElementById(‘book‘)
    var several = document.getElementById(‘several‘);

    animate(book, {
    left: 50,
    duration: 2000
    })

    function animate(elem, options){
    //动画初始值
    var start = 500
    //动画结束值
    var end = options.left

    var createTime = function(){
    return (+new Date)
    }
    //动画开始时间
    var startTime = createTime();

    var timerId;

    //开始动画
    var startAnim = function() {
    timerId = requestAnimationFrame(tick,15);
    }
    //停止动画
    var stopAnim = function() {
    cancelAnimationFrame(timerId)
    }

    var i = 0;

    function tick(){
    i++;
    several.innerHTML = ‘requestAnimationFrame调用次数:‘ + i;
    //每次变化的时间
    var remaining = Math.max(0, startTime + options.duration - createTime())
    var temp = remaining / options.duration || 0;
    var percent = 1 - temp;
    var setStyle = function(value){
    elem.style[‘left‘] = value + ‘px‘
    }
    //移动的距离
    var now = (end - start) * percent + start;
    if(percent === 1){
    setStyle(now)
    stopAnim() ;
    }else{
    setStyle(now)
    startAnim(tick);
    }
    }

    //开始执行动画
    startAnim(tick);
    }
    </script>

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

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

    时间: 2024-10-11 20:24:38

    动画requestAnimationFrame的相关文章

    window.requestAnimationFrame() ,做逐帧动画,你值得拥有

    window.requestAnimationFrame() 方法告诉浏览器您希望执行动画,并请求浏览器调用指定的函数在下一次重绘之前更新动画.该方法使用一个回调函数作为参数,这个回调函数会在浏览器重绘之前调用. 如果你想做逐帧动画的时候,你应该用这个方法.这就要求你的动画函数执行会先于浏览器重绘动作.通常来说,被调用的频率是每秒60次,但是一般会遵循W3C标准规定的频率.如果是后台标签页面,重绘频率则会大大降低. 基本语法: requestID = window.requestAnimatio

    requestAnimationFrame动画方法

    一.动画方式 在HTML5/CSS3时代,实现动画的方式有许多种: 你可以用css3的animation和@keyframes: 可以用css3的transition: 还可以用原始的setTimeout().setInterval()达到动画效果,以及jQuery中animate方法: 今天我们要介绍是另一种动画方式:requestAnimationFrame(callback)! 二.基本语法 可以直接调用,也可以通过window来调用,接收一个函数作为回调,返回一个ID值: ID=requ

    requestAnimationFrame,Web中写动画的另一种选择

    HTML5/CSS3时代,我们要在web里做动画选择其实已经很多了: 你可以用CSS3的animattion+keyframes; 你也可以用css3的transition; 你还可以用通过在canvas上作图来实现动画,也可以借助jQuery动画相关的API方便地实现; 当然最原始的你还可以使用window.setTimout()或者window.setInterval()通过不断更新元素的状态位置等来实现动画,前提是画面的更新频率要达到每秒60次才能让肉眼看到流畅的动画效果. 现在又多了一种

    转: requestAnimationFrame,Web中写动画的另一种选择

    HTML5/CSS3时代,我们要在web里做动画选择其实已经很多了: 你可以用CSS3的animattion+keyframes; 你也可以用css3的transition; 你还可以用通过在canvas上作图来实现动画,也可以借助jQuery动画相关的API方便地实现; 当然最原始的你还可以使用window.setTimout()或者window.setInterval()通过不断更新元素的状态位置等来实现动画,前提是画面的更新频率要达到每秒60次才能让肉眼看到流畅的动画效果. 现在又多了一种

    js 动画方法之requestAnimationFrame

    js动画实现的方法到现在有三种 1 css3: 通过animattion+keyframes;或 transition 2. setTimeout/setInterval: setTimeout/setInterval:通过递归调用同一方法来不断更新动画元素以达到动起来的效果,动画过度绘制,浪费 CPU 周期以及消耗额外的电能等问题. 3.requestAnimationFrame: requestAnimationFrame:是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用

    动画性能优化-requestanimationframe、GPU等

    最近在做一个场景动画,有一个欢迎界面和一个主动画界面,两个界面之间的连接通过一个进度条来完成,当进度条完成,提供通往主动画的按钮. 画面会从一个个的场景移动过去,用户可通过点击抽奖.查看气泡商铺等进行交互,同时可拖动画面,前移或后退.该项目中,出了主动画,还有人物场景对话的动画等,性能的优化.用户的体验变得尤为重要,这里总结一下在开发过程中使用的一些性能.体验优化方法. 1.动画 a.优先采用requestanimationframe,实现动画帧的并发渲染: b.做减法:兼容低版本浏览器(a中的

    性能更好的js动画实现方式——requestAnimationFrame

    本文转载,原文地址:http://www.cnblogs.com/2050/p/3871517.html 用js来实现动画,我们一般是借助setTimeout或setInterval这两个函数,css3动画出来后,我们又可以使用css3来实现动画了,而且性能和流畅度也得到了很大的提升.但是css3动画还是有不少局限性,比如不是所有属性都能参与动画.动画缓动效果太少.无法完全控制动画过程等等.所以有的时候我们还是不得不使用setTimeout或setInterval的方式来实现动画,可是setTi

    window.requestAnimationFrame与Tween.js配合使用实现动画缓动效果

    window.requestAnimationFrame 概述 window.requestAnimationFrame()这个方法是用来在页面重绘之前,通知浏览器调用一个指定的函数,以满足开发者操作动画的需求.这个方法接受一个函数为参,该函数会在重绘前调用. 注意: 如果想得到连贯的逐帧动画,函数中必须重新调用 requestAnimationFrame(). 如果你想做逐帧动画的时候,你应该用这个方法.这就要求你的动画函数执行会先于浏览器重绘动作.通常来说,被调用的频率是每秒60次,但是一般

    基于脚本的动画的计时控制(“requestAnimationFrame”)(转)

    requestAnimationFrame 方法的支持,该方法通过在系统准备好绘制动画帧时调用该帧,从而为创建动画网页提供了一种更平滑更高效的方法.在此 API 之前,使用 setTimeout 和 setInterval 绘制的动画并没有为 Web 开发人员提供有效的方法来规划动画的图形计时器.这导致了动画过度绘制,浪费 CPU 周期以及消耗额外的电能等问题.而且,即使看不到网站,特别是当网站使用背景选项卡中的页面或浏览器已最小化时,动画都会频繁出现. 当动画使用分辨率为 10ms 的 Jav