JavaScript 中的 requestAnimationFrame 递归 - 为什么它不会因为资源耗尽而崩溃?



给定以下 psudo 代码(取自我的远程相机机器人项目(

[event handler](when event happens) {
[do some startup and init code]
start_everything_going();
}
// This block does something that will interact with the browser every 1/60 second.
def do_something() {
[code that does something goes here]
requestAnimationFrame(do_something);
}
def start_everything_going() {
requestAnimationFrame(do_something);
}

使用 requestAnimationFrame 的工作方式是事件处理程序触发(例如,当连接或激活操纵杆时(,并且在运行某些设置或配置代码后,它会调用初始函数以开始循环动画 - start_everything_going((。

由于 requestAnimationFrame 运行一次,并且仅在调用时运行一次,因此必须重复调用它才能创建连续效果。

规范的方法 - 以及我见过的每个示例中使用的方法 - 是第一次调用由触发它的事件处理程序调用的包装函数(最终(完成,或者事件处理程序启动的东西。

为了重复调用requestAnimationFrame,实际的animating函数调用requestAnimationFrame,将自身作为参数,作为退出前的最后一件事。

据我所知,这是递归,在我见过的所有关于requestAnimationFrame的文档中都称为递归。(MDN、Stack Overflow 等(。

我记得,对函数的递归调用会创建该函数的另一个实例(将原始实例及时挂起在某个地方(,重复执行某些操作所需的步骤。 这种情况永远持续下去,创造额外的自身实例,直到(最终(达到某种结束条件。

由于在这种情况下,被调用的函数永远不会返回,因此无法"展开"递归。 而且,据我所知,这种情况将持续到地狱冻结或所有可用的计算机资源都耗尽为止。

由于此动画每 1/60 秒刷新一次,并且(理论上(可以运行数小时、数小时、数小时、数小时,那么是什么阻止它像纸牌屋一样折叠起来并因资源耗尽而使系统崩溃?

它实际上不是函数堆栈意义上的递归调用,只是广义上的递归调用。

当您调用requestAnimationFrame(callbackFunction)时,requestAnimationFrame函数与浏览器一起调度回调函数,以便在浏览器的下一帧调用。然后requestAnimationFrame返回并从堆栈中弹出,函数堆栈完成执行,直到其他所有函数返回并从堆栈中弹出,并将控制权交还给浏览器。

换句话说,堆栈完全解析,然后在下一帧,浏览器通过执行callbackFunction再次启动函数堆栈。

函数调用自身是经典递归,当复杂算法需要重复自身时,这在编程中很常见(例如计算数学序列或无理数的许多位数字,如π(。

这里有一个重要的区别。requestAnimationFrame实际上并不直接调用自己。callbackFunction调用requestAnimatonFrame,然后标记浏览器在下一帧调用callbackFunction。然后requestAnimationFrame返回,函数堆栈继续完全解析。

由于在这种情况下,被调用的函数永远不会返回,因此无法"展开"递归。

从技术上讲,被调用的函数返回每一帧,然后浏览器在下一帧再次执行它。

相关内容

最新更新