使用 requestAnimationFrame 替代 setInterval

Avatar of Chris Coyier
Chris Coyier

在动画方面,我们被告知 setInterval 是个坏主意。例如,循环将不顾其他任何正在进行的事情而运行,而不是像 requestAnimationFrame 那样礼貌地让步。此外,一些浏览器可能会对 setInterval 循环进行“追赶”,其中一个不活动的选项卡可能一直在排队迭代,然后在再次变为活动状态时非常快地运行所有这些迭代以追赶。

如果你想使用 setInterval,但又想要 requestAnimationFrame 的性能礼貌,互联网上有一些可用的选项!

来自 Serguei Shimansky

var requestInterval = function (fn, delay) {
  var requestAnimFrame = (function () {
    return window.requestAnimationFrame || function (callback, element) {
      window.setTimeout(callback, 1000 / 60);
    };
  })(),
  start = new Date().getTime(),
  handle = {};
  function loop() {
    handle.value = requestAnimFrame(loop);
    var current = new Date().getTime(),
    delta = current - start;
    if (delta >= delay) {
      fn.call();
      start = new Date().getTime();
    }
  }
  handle.value = requestAnimFrame(loop);
  return handle;
};

查看评论 以了解各种变体,例如清除间隔、设置和清除超时。

这是 Joe Lambert 版本的一个变体

window.requestInterval = function(fn, delay) {
  if( !window.requestAnimationFrame       && 
    !window.webkitRequestAnimationFrame && 
    !(window.mozRequestAnimationFrame && window.mozCancelRequestAnimationFrame) && // Firefox 5 ships without cancel support
    !window.oRequestAnimationFrame      && 
    !window.msRequestAnimationFrame)
      return window.setInterval(fn, delay);
      
  var start = new Date().getTime(),
    handle = new Object();
    
  function loop() {
    var current = new Date().getTime(),
      delta = current - start;
      
    if(delta >= delay) {
      fn.call();
      start = new Date().getTime();
    }

    handle.value = requestAnimFrame(loop);
  };
  
  handle.value = requestAnimFrame(loop);
  return handle;
}

  window.clearRequestInterval = function(handle) {
  window.cancelAnimationFrame ? window.cancelAnimationFrame(handle.value) :
  window.webkitCancelAnimationFrame ? window.webkitCancelAnimationFrame(handle.value) :
  window.webkitCancelRequestAnimationFrame ? window.webkitCancelRequestAnimationFrame(handle.value) : /* Support for legacy API */
  window.mozCancelRequestAnimationFrame ? window.mozCancelRequestAnimationFrame(handle.value) :
  window.oCancelRequestAnimationFrame ? window.oCancelRequestAnimationFrame(handle.value) :
  window.msCancelRequestAnimationFrame ? window.msCancelRequestAnimationFrame(handle.value) :
  clearInterval(handle);
};

这在一定程度上更加冗长,因为它处理了供应商前缀。你很可能不需要供应商前缀。查看 requestAnimationFrame 的浏览器支持。如果你需要支持 IE 9 或 Android 4.2-4.3,你根本无法使用它。供应商前缀仅对相当旧版本的 Safari 和 Firefox 有帮助。

还有另一个来自 StackExchange 的方法

window.rInterval=function(callback,delay) {
  var dateNow=Date.now,
    requestAnimation=window.requestAnimationFrame,
    start=dateNow(),
    stop,
    intervalFunc=function() {
      dateNow()-start<delay||(start+=delay, callback());
      stop||requestAnimation(intervalFunc)
    }
  requestAnimation(intervalFunc);
  return {
    clear: function(){ stop=1 }
  }
}