Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/440.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 无尽的动画、requestAnimationFrame和调用堆栈限制_Javascript_Requestanimationframe - Fatal编程技术网

Javascript 无尽的动画、requestAnimationFrame和调用堆栈限制

Javascript 无尽的动画、requestAnimationFrame和调用堆栈限制,javascript,requestanimationframe,Javascript,Requestanimationframe,我有一个小项目,我正在工作的消费推特流API,并使一个小画布动画从它。考虑到推特流媒体API没有得出结论,动画可能会无限期地继续下去 这就是问题所在requestAnimationFrame似乎通过递归进行操作,直到ES6,我们才得到正确的尾部调用,这意味着我认为这会增加每个帧的调用堆栈 问题是,这最终会因为超过最大调用堆栈大小而引发错误,这是对的,还是浏览器为了避免这个限制而耍了一个花招?requestAnimationFrame真的做了一些我不理解的奇怪的事情吗(可能是沿着setInterv

我有一个小项目,我正在工作的消费推特流API,并使一个小画布动画从它。考虑到推特流媒体API没有得出结论,动画可能会无限期地继续下去

这就是问题所在
requestAnimationFrame
似乎通过递归进行操作,直到ES6,我们才得到正确的尾部调用,这意味着我认为这会增加每个帧的调用堆栈

问题是,这最终会因为超过最大调用堆栈大小而引发错误,这是对的,还是浏览器为了避免这个限制而耍了一个花招?
requestAnimationFrame
真的做了一些我不理解的奇怪的事情吗(可能是沿着
setInterval
不是递归的路线)

在chrome 36.0.1985.32 beta版(其调用堆栈大小为20834)中,我正在测试:

function test(t) {
    requestAnimationFrame(test);
}

test(performance.now());
没有看到任何问题。我预计会抛出一个
RangeError
,假设每秒60帧,大约6分钟

另一个误导性信息显示在chrome developer tools窗口的Call Stack部分,其中显示了
requestAnimationFrame
调用堆栈,因为它将填充堆栈,如下图所示:


英国皇家空军将启动“在下一个绘制帧上”功能。这意味着它将在另一个操作堆栈中执行,并且不会出现任何最大调用堆栈错误。

如果
requestAnimationFrame
调用
test
,那么确实会有一个无限的调用堆栈。很明显,
test
do调用
requestAnimationFrame
。需要验证
requestAnimationFrame
是否调用
test

以下代码将发现:

function testSnitch(t) {
    var caller = arguments.callee.caller || 'NULL';
    console.log(caller.toString());
    requestAnimationFrame(test);
}

testSnitch(performance.now());
是的,requestAnimationFrame()是异步递归的,可以防止任何实际的堆栈溢出。但不要忘记,堆栈在最后仍然会展开。如果正在运行单个动画,则没有问题。但是,如果您按顺序运行一系列动画,您可能会执行以下操作:

function animateFirst(timeStamp) {
    let r = functionReturnValue();
    if (r == "complete") {
        frame = requestAnimationFrame(animateNext);
        return; // this is necessary
    }
    frame = requestAnimationFrame(animateFirst);
}
或者,您必须以这种方式构建它:

function animateFirst(timeStamp) {
    let r = functionReturnValue();
    if (r == "complete") {
        frame = requestAnimationFrame(animateNext);
    }
    else {
        frame = requestAnimationFrame(animateFirst);
    }
}

这些例子过于简单化了。在实际的动画函数中,可能有更复杂的逻辑。关键是,如果在第一个示例中省略return语句,则animateFirst()将在animateNext()完成并展开其异步堆栈后再次运行。根据您的代码,它可能会运行一次,也可能会启动一个全新的动画循环。

您是否从阅读开始,它对此进行了很好的解释。文档中没有明确说明上述问题的答案。最接近的答案(据我所知)这将要求在浏览器执行下一次重新绘制之前调用动画函数,这意味着它是非递归的。我想要比那更明确的。是的。这是愚蠢的表现。它不是同步递归的。不确定“非递归”是什么意思,函数本身当然是非递归的,但将它放在递归调用的函数中会使它递归,它每秒调用回调大约60次,具体取决于浏览器,这都在文档中。由于它是异步的,并且在下次重新绘制之前调用回调,因此不会出现调用堆栈错误。Argh。真是个愚蠢的屁。是的,任何类型的异步函数都没有限制,因为每个函数都在不同的事件循环迭代中。。。