requestAnimationFrame 实现是递归的吗?

Is requestAnimationFrame implementation's recursive?

我目前正在试验 three.js,它依赖于 requestAnimationFrame 来执行动画。

在调用立方体旋转和 renderer.render 函数之前,以下代码不会导致无限递归吗?

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

代码有效,但我正在努力提高我对 JavaScript 的整体理解。

在我看来,render 是作为回调函数调用的。但这是否意味着 JavaScript 继续 运行 通过函数中的代码 停止继续下一个调用之前?

这只要求浏览器在下一个渲染循环之前调用您的回调:

You should call this method whenever you're ready to update your animation onscreen. This will request that your animation function be called before the browser performs the next repaint.

所以这里没有递归,你的函数继续执行。

您也可以使用 cancelAnimationFrame 取消回叫请求。

here.

在第一次 render() 调用之后,RequestAnimationFrame 将异步处理您的渲染函数,每秒调用它约 60 次。您的函数不是递归的,因为 Javascript 将继续执行代码。

但是,您应该只在渲染函数的最后使用 RequestAnimationFrame,作为函数的最后一个命令。想象一下你有一个大场景,有很多动画:在完成参数更新之前请求下一帧,可能会造成巨大的混乱。

您还可以使用 setTimeout 来处理动画,以所需的帧速率调用渲染方法,如下所示:

var desideredFrameRate = 60;

window.myRequestAnimationFrame = function(callback) {

    setTimeout(callback, 1000/desiredFrameRate);

}

不,堆栈不会爆炸,因为 requestAnimationFrame's callback is executed asynchronously. Async code is never run until the entire call stack is cleared. See this video 对事件循环的解释。

考虑这个演示来说明:

const fakeRAF = cb => setTimeout(cb);

(function rerender() {
  fakeRAF(rerender);
  console.log(Date.now());
})();

你可以让这个 运行 一整天。当然,requestAnimationFramefakeRAF 做了更多的工作,本质上是非常聪明地计算何时触发 cb,但是这个简单的演示足以证明它不是递归的,感谢setTimeout 提供异步 API.

顺便说一下, requestAnimationFramefakeRAF 是在函数的顶部还是底部调用。函数中的所有同步代码都必须 运行 在触发回调之前,这样就不会出现下一帧踩到前一帧或类似情况的问题。