requestAnimationFrame-制作逐帧动画

2017-04-02  本文已影响0人  壮哉我大前端

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

浏览器的显示频率一般是16.7ms,我们将setTimeout的间隔时间设为16.7ms,节奏会如下图第一行展示 。但如果我们将间隔时间设为10ms,那么节奏会如下图第二行展示。


frame-lost.png

举个例子:

国庆北京高速,最多每16.7s通过一辆车,结果,突然插入一批setTimeout的军车,强行要10s通过。显然,这是超负荷的,要想顺利进行,只能让第三辆车直接消失(正如显示绘制第三帧的丢失)。然而,这是不现实的,于是就有了会堵车!

同样的,显示器16.7ms刷新间隔之前发生了其他绘制请求(setTimeout),导致所有第三帧丢失,继而导致动画断续显示(堵车的感觉),这就是过度绘制带来的问题。不仅如此,这种计时器频率的降低也会对电池使用寿命造成负面影响,并会降低其他应用的性能。

这也是为何setTimeout的定时器值推荐最小使用16.7ms的原因(16.7 = 1000 / 60, 即每秒60帧)。

而requestAnimationFrame就是为了解决这个问题而出现的。它所做的事情很简单,就是跟着浏览器的绘制走,如果浏览设备绘制间隔是16.7ms,那它就在这个间隔绘制。如果浏览设备绘制间隔是10ms,它就10ms绘制。这样就不会存在过度绘制的问题,动画不会掉帧,播放自然流畅。

兼容性

2017-04-02_112747.jpg

统一的向下兼容方法:

(function() {
  var lastTime = 0;
  var vendors = ['webkit', 'moz'];
  for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
    window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
    window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] ||    // Webkit中此取消方法的名字变了
    window[vendors[x] + 'CancelRequestAnimationFrame'];
  }

  if (!window.requestAnimationFrame) {
    window.requestAnimationFrame = function(callback, element) {
      var currTime = new Date().getTime();
      var timeToCall = Math.max(0, 16.7 - (currTime - lastTime));
      var id = window.setTimeout(function() {
        callback(currTime + timeToCall);
      }, timeToCall);
      lastTime = currTime + timeToCall;
      return id;
    };
  }
  if (!window.cancelAnimationFrame) {
    window.cancelAnimationFrame = function(id) {
        clearTimeout(id);
    };
  }
}());

原文来自:http://www.zhangxinxu.com/wordpress/?p=3695

上一篇下一篇

猜你喜欢

热点阅读