7

发生什么事情可以让循环的其余部分执行,然后让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); 
}; 
+2

你可以发表一些代码吗? –

+0

[请求动画帧以获得更佳性能](http://html5hub.com/request-animation-frame-for-better-performance/),[用于智能动画制作的requestAnimationFrame](http://www.paulirish.com/2011/requestanimationframe-for-smart-animating /) – Andreas

+1

requestAnimationFrame不是递归的,它是异步的(就像一个简短的setTimeout,但更有效率),并在被调用的函数的主体之后执行。但是,它在for循环。顺便说一句,递归发生在render函数中,而不是在requestAnimationFrame中,你不是在render中调用render。 – mpm

回答

10

请让我知道,如果我完全脱离基地;我之前没有使用动画内容。我看到了使用​​一个例子是:

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

你想知道为什么animloop,因为它传递到requestAnimFrame不会导致无限循环时,它随后被叫什么名字?

这是因为这个函数不是真正的递归。您可能会认为当您致电requestAnimFrame时立即致电animloop。并非如此! requestAnimFrame是异步的。所以这些语句按照你看到的顺序执行。这意味着主线程不会等待用于呼叫requestAnimFrame返回,之前呼叫render()。所以render()几乎立即被调用。然而,回调(在这种情况下是animloop)是而不是立即调用。它可能是在未来的某个时间点,您已经从第一个退出animloop调用。对animloop的这个新调用具有其自己的上下文和堆栈,因为它实际上尚未从第一个animloop调用的内的中调用。这就是为什么你不会以无限递归和堆栈溢出结束的原因。

+1

好吧,现在更有意义,我对使用回调的理解仍然不稳定,所以我不得不做一些研究。 谢谢:) – dnv

5

这是发生了什么:

声明一个函数的定义,请拨打​​功能。

其中日程你的函数中调用和执行时再一次是正确的,这是下一帧是16毫秒后通常。另外,这种调度是异步的。它不会停止执行下面的代码。所以它不像低于这条线的代码在16ms过去之前不会工作。

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

但是,如果函数花费更长的时间才能完成,下一帧将被延迟,因此不会执行调用同一个函数的计划任务。

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

+0

基于我的测试和有限的理解,raf并不一定会在第一次被调用时等待下一帧。第一次通常几乎立即运行(刚刚0.4毫秒,当我用铬进行测试时)的原因是它的运行速度与下一帧之前的速度一样快。但是当它在递归循环中被调用时,循环中的第二个和所有后续调用将被去抖动为帧率。我可能是完全错误的,只是我最好的猜测。我只是很难浏览器在0.4ms内渲染帧,当它不必。 –

+0

raf试图通过运行不会显示的代码来浪费资源。假设帧在10ms处得到更新。并且您的代码循环约5毫秒。那么你的代码会告诉浏览器做两次绘画,但它只做最后一件事,这是raf可以防止的。如果浏览器可以更快地更新帧,那么代码运行得更快。反过来说,你的代码需要20ms,浏览器可以在10ms更新。那么如果没有任何变化,浏览器将会延迟更新,那么更新没有意义。从而节省计算资源。 –

1

出于同样的原因,在一个循环调度与setTimeout回调不会导致无限递归,它时间表JS event loop而不是立即执行它的下一个电话。

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

Event loop diagram

该图是用于达特,但概念是在JS相同。如果您有兴趣阅读有关事件循环,计划计时器以及微任务和宏任务之间差异的更多信息,请查阅this question

相关问题