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

时间:2014-06-01 11:23:55

标签: javascript requestanimationframe

我有一个小项目,我正在努力消耗twitter流API并从中制作一个小画布动画。鉴于Twitter流媒体API没有结束,动画可以无限期地继续。

存在问题。 requestAnimationFrame似乎通过递归操作,我们在ES6之前没有得到正确的尾调用,这意味着我认为这会增加每帧的调用堆栈。

问题是,我是否正确,这最终会因为超出最大调用堆栈大小而引发错误,或者浏览器是否会发挥作用以避免限制? requestAnimationFrame真的做了一件我不理解的奇怪的事情(可能是setInterval不是递归的吗?)

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

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

test(performance.now());

并且没有看到任何问题。假设60fps,我希望抛出RangeError ~6分钟。

另一个误导性信息显示在chrome开发人员工具窗口的“调用堆栈”部分中,其中显示了requestAnimationFrame调用堆栈,因为它将填满堆栈,如下图所示:

enter image description here

3 个答案:

答案 0 :(得分:3)

RAF将在下一个绘制的框架"上启动功能"。这意味着它将在另一堆操作中执行,并且您不会有任何最大调用堆栈错误。

答案 1 :(得分:0)

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

以下代码将会找到:

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

testSnitch(performance.now());

答案 2 :(得分:0)

是的,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()完成并取消其异步堆栈后再次运行。根据您的代码,它可能会运行一次,或者可能会开始一个全新的动画循环。