为什么在循环开始时调用requestAnimationFrame不会导致无限递归?

时间:2014-02-18 21:57:17

标签: javascript animation stack-overflow requestanimationframe

是什么让循环的其余部分执行,然后requestAnimationFrame执行下一帧?

我误解了这种方法是如何工作的,并且无法在任何地方看到明确的解释。我尝试在这里阅读时间规范http://www.w3.org/TR/animation-timing/,但我无法弄清楚它是如何工作的。

编辑:

例如,此代码取自threejs文档。

var render = function () { 
requestAnimationFrame(render); 
cube.rotation.x += 0.1; 
cube.rotation.y += 0.1;
renderer.render(scene, camera); 
};

3 个答案:

答案 0 :(得分:11)

如果我完全偏离基地,请告诉我。我之前没有使用动画的东西。我看到使用requestAnimationFrame的一个例子是:

(function animloop(){
  requestAnimFrame(animloop);
  render();
})();

您是否想知道为什么animloop被传递到requestAnimFrame时,在随后被调用时不会导致无限循环?

这是因为此函数不是真正的递归。您可能会认为在致电animloop时会立即调用requestAnimFrame。不是这样! requestAnimFrame是异步的。因此,语句按您看到的顺序执行。这意味着主线程没有等待来调用requestAnimFrame来回复,之后调用render()。所以render()几乎立即被召唤。但是回调(在本例中为animloop)是不是立即调用。当您已经退​​出第一次animloop的调用时,可能会在以后的某个时间点被调用。这个对animloop的新调用有自己的上下文和堆栈,因为它实际上没有从在第一个animloop调用的执行上下文中调用。这就是为什么你最终没有无限递归和堆栈溢出。

答案 1 :(得分:5)

这就是:

你声明一个函数定义,调用requestAnimationFrame函数。

计划您的函数在时间正确时再次被调用和执行,这通常是在16ms之后的下一帧。此外,此调度是异步的。它不会停止在它下面执行代码。因此,直到16ms过去,这条线下面的代码才会起作用。

但是,在大多数情况下,功能会在3-4毫秒内执行。

但是如果函数需要更长时间才能完成,那么下一帧将被延迟,从而不会执行计划任务,即再次调用相同的函数。

从某种意义上说,动画是无限循环。 requestAnimationFrame的目标是什么。但是,此非阻塞无限循环受帧/ fps 的限制。

答案 2 :(得分:1)

出于同样的原因,在循环中使用setTimeout调度回调不会导致无限递归,计划 JS event loop >而不是立即执行。

调用不是在当前上下文中进行的,因此从严格意义上讲,它在技术上不是递归,并且不会导致堆栈限制超出错误。

Event loop diagram

此图表适用于Dart,但JS中的概念相同。如果您有兴趣阅读有关事件循环,调度计时器以及微任务和宏任务之间差异的更多信息,请查看this question