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

Javascript 为什么在循环开始时调用requestAnimationFrame不会导致无限递归?,javascript,animation,stack-overflow,requestanimationframe,Javascript,Animation,Stack Overflow,Requestanimationframe,是什么让循环的其余部分执行,然后让requestAnimationFrame执行下一帧 我误解了这种方法的工作原理,在任何地方都看不到清晰的解释。我试着在这里阅读计时规范,但我不明白它是如何工作的 例如,此代码取自threejs文档 var render = function () { requestAnimationFrame(render); cube.rotation.x += 0.1; cube.rotation.y += 0.1; renderer.render(

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

我误解了这种方法的工作原理,在任何地方都看不到清晰的解释。我试着在这里阅读计时规范,但我不明白它是如何工作的

例如,此代码取自threejs文档

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

请让我知道,如果我完全离开基地;我以前没用过动画。我看到的一个使用
requestAnimationFrame
的示例是:

(function animloop(){
  requestAnimFrame(animloop);
  render();
})();
您想知道为什么
animloop
在传递到
requestAnimFrame
时,在随后调用它时不会导致无限循环吗

这是因为这个函数不是真正的递归函数。您可能认为调用
requestAnimFrame
时会立即调用
animloop
。不是这样<代码>请求帧是异步的。因此,这些语句是按照您看到的顺序执行的。这意味着主线程在调用
render()
之前不会等待
requestAnimFrame
的调用返回。因此几乎立即调用
render()
。但是,不会立即调用回调(在本例中为
animloop
)。当您已经从对
animloop
的第一次调用退出时,它可能会在将来的某个时候被调用。这个对
animloop
的新调用有自己的上下文和堆栈,因为它实际上没有从第一个
animloop
调用的执行上下文中被调用。这就是为什么最终不会出现无限递归和堆栈溢出

情况就是这样:

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

哪个计划在适当的时候再次调用和执行函数,这是通常在16ms之后的下一帧。此外,此调度是异步的。它不会停止下面代码的执行。所以这并不是说这行下面的代码要到16毫秒后才能工作

然而,在大多数情况下,函数在3-4毫秒内执行

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


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

同样的原因是,在循环中使用
setTimeout
调度回调不会导致无限递归,它调度下一次调用,而不是立即执行

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


(来源:)


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

您能发布一些代码吗?“requestAnimationFrame”不是递归的,它是异步的(就像短的setTimeout,但效率更高)并在调用它的函数体之后执行。然而,将它放入for循环中没有什么意义。递归发生在render函数中,而不是requestAnimationFrame中。顺便说一下,您没有在render中调用render。好了,现在这更有意义了,我对使用回调的理解还不太清楚,所以我必须做一些研究。谢谢:)这是一个非常简洁的回答,澄清了我对同一个问题的困惑。我认为这应该是公认的答案:)基于我的测试和有限的理解,raf不一定要等到下一帧第一次呼叫。它第一次几乎立即运行(刚才我在chrome中测试时为0.4ms)的原因是,它在下一帧之前以尽可能快的速度运行。但是当它在递归ish循环中被调用时,循环中的第二次调用和所有后续调用都将被取消到帧速率。我可能完全错了,只是我对发生了什么的最好猜测。我只是觉得浏览器很难在0.4ms内渲染一帧,尤其是在不需要渲染的情况下。raf试图通过运行不会显示的代码来避免浪费资源。假设帧以10毫秒的速度更新。你的代码循环大约5毫秒。然后你的代码告诉浏览器做两次绘制,但它只做最后一件事,这是raf阻止的。如果浏览器可以更快地更新帧,那么代码运行得更快。反过来说,你的代码需要20毫秒,浏览器可以在10毫秒更新。如果没有任何变化,那么更新就没有意义了。浏览器会延迟更新。从而节省了计算资源。