Javascript 有限帧速率下的requestAnimationFrame

Javascript 有限帧速率下的requestAnimationFrame,javascript,Javascript,据我所知,JSrequestAnimationFrameAPI的使用是针对帧速率不需要控制的情况,但我有一个用例,其中一个只在一定的fps间隔(可能在1到25帧/秒之间)进行更新是至关重要的。那么,我还能有效地使用rAF来获得它提供的优化吗 与我的答案有相似之处,但在这个问题的背景下,我几乎没有任何意义 我有两种可能的解决办法。第一个涉及使用while循环在从回调调用requestAnimationFrame之前在指定的延迟内停止脚本的执行。在我看到的示例中,它有效地限制了动画的fps,但似乎也

据我所知,JS
requestAnimationFrame
API的使用是针对帧速率不需要控制的情况,但我有一个用例,其中一个
只在一定的fps间隔(可能在1到25帧/秒之间)进行更新是至关重要的。那么,我还能有效地使用rAF来获得它提供的优化吗

与我的答案有相似之处,但在这个问题的背景下,我几乎没有任何意义

我有两种可能的解决办法。第一个涉及使用
while
循环在从回调调用
requestAnimationFrame
之前在指定的延迟内停止脚本的执行。在我看到的示例中,它有效地限制了动画的fps,但似乎也降低了整个选项卡的速度。这仍然是一个好的解决方案吗?第二种选择,正如我在上面链接的问题中提到的,在
setInterval
内调用
requestAnimationFrame
。对我来说,这似乎有点复杂,但这可能是最好的选择


或者有更好的替代方案来实现这一点吗?

您可以做什么,尽管我不知道这是否真的更好:

  • 使用
    requestAnimationFrame
  • 使用固定fps使用
    setInterval
    更新可见上下文
例如:

<canvas id="canvas"></canvas>​

<script type="text/javascript">
  (function () {
    var
      ctxVisible = document.getElementById('canvas').getContext('2d'),
      ctxHidden = document.createElement('canvas').getContext('2d');

    // quick anim sample
    (function () {
      var x = 0, y = 75;

      (function animLoop() {
        // too lazy to use a polyfill here
        webkitRequestAnimationFrame(animLoop);

        ctxHidden.clearRect(0, 0, 300, 150);
        ctxHidden.fillStyle = 'black';
        ctxHidden.fillRect(x - 1, y - 1, 3, 3);

        x += 1;
        if (x > 300) {
          x = 0;
        }
      }());
    }());

    // copy the hidden ctx to the visible ctx on a fixed interval (25 fps)
    setInterval(function () {
      ctxVisible.putImageData(ctxHidden.getImageData(0, 0, ctxHidden.canvas.width, ctxHidden.canvas.height), 0, 0);
    }, 1000/40);
  }());
</script>
​
(功能(){
变量
ctxsible=document.getElementById('canvas').getContext('2d'),
ctxHidden=document.createElement('canvas').getContext('2d');
//快速动画样本
(功能(){
变量x=0,y=75;
(函数animLoop(){
//懒得在这里使用多边形填充
webkitRequestAnimationFrame(animLoop);
ctxHidden.clearRect(0,0300150);
ctxHidden.fillStyle='black';
ctxHidden.fillRect(x-1,y-1,3,3);
x+=1;
如果(x>300){
x=0;
}
}());
}());
//以固定间隔(25 fps)将隐藏的ctx复制到可见的ctx
setInterval(函数(){
ctxsible.putImageData(ctxHidden.getImageData(0,0,ctxHidden.canvas.width,ctxHidden.canvas.height),0,0);
}, 1000/40);
}());

演示:

Yoshi的答案可能是解决此问题的最佳代码解决方案。但我还是会把这个答案标记为正确的,因为经过一些研究,我基本上发现我的问题是无效的
requestAnimationFrame
实际上是为了尽可能地保持帧速率,并针对动画要保持一致和平滑的场景进行优化

但是值得注意的是,您不需要
requestAnimationFrame
来获得优化(尽管rAF被吹捧为一个伟大的性能提升器),因为浏览器仍然优化
的常规绘图。例如,当选项卡未聚焦时,Chrome For one停止绘制画布


所以我的结论是,这个问题是无效的。希望这能帮助任何想知道类似我的事情的人。

这只是一个概念证明

我们所做的就是设置每秒帧数和每帧之间的间隔。在绘图函数中,我们从当前时间中扣除最后一帧的执行时间,以检查从最后一帧开始经过的时间是否超过我们的间隔(基于fps)。如果条件的计算结果为true,我们将为当前帧设置时间,该时间将是下一次图形调用中的“最后一帧执行时间”

var Timer = function(callback, fps){
  var now = 0;
  var delta = 0;
  var then = Date.now();

  var frames = 0;
  var oldtime = 0;

  fps = 1000 / (this.fps || fps || 60);

  return requestAnimationFrame(function loop(time){
    requestAnimationFrame(loop);

    now = Date.now();
    delta = now - then;

    if (delta > fps) {
      // Update time stuffs
      then = now - (delta % fps);

      // Calculate the frames per second.
      frames = 1000 / (time - oldtime)
      oldtime = time;

      // Call the callback-function and pass
      // our current frame into it.
      callback(frames);
    }
  });
};
用法:

var set;
document.onclick = function(){
  set = true;
};

Timer(function(fps){
  if(set) this.fps = 30;
  console.log(fps);
}, 5);

我现在正在测试一些代码…:)您需要固定帧速率来计算内容还是仅用于显示目的?固定帧速率用于显示目的。非常感谢您的回答和提琴-非常感谢!然而,我认为我的问题真的是无效的,所以我觉得我不能把这个标记为可接受的答案。我想你的结论绝对正确。因此,让这个被接受的答案可能对未来读者更有帮助。你会考虑添加一些叙述来解释为什么这个代码会起作用,是什么使它成为问题的答案呢?这对提出问题的人和其他任何人来说都是非常有帮助的。这里发生了很多事情,但这是一个非常聪明的解决方案。我可能会尝试将其集成到我的代码中,如果在此之前没有发生任何其他事情,我会尝试回到这里,并在工作完成后添加一些编辑和进一步的解释。我添加了一些解释文本。希望有帮助。