如何使用 `requestAnimationFrame` 停止递归循环

How to stop recursive loop with `requestAnimationFrame`

我有一个 class 的递归循环函数,如下所示:

class Foo {
    private isLoopOnFlg: boolean = false;

    public StartLoop() {
        this.isLoopOnFlg = true;

        this.recursiveLoopWithDelay(() => {
            // Modifying DOM objects
        }, 1000);
    }

    public StopLoop() {
        this.isLoopOnFlg = false;
    }

    // THE PROBLEM
    private recursiveLoopWithDelay(loopFn: any, delay: number) {
        let stamp = Date.now();

        // How do I stop the loop using `isLoopOnFlg`?
        function _loop() {
            if (Date.now() - stamp >= delay) {
                loopFn();
                stamp = Date.now();
            }

            window.requestAnimationFrame(_loop);
        }

        window.requestAnimationFrame(_loop);
    }
}

如您所见,函数 recursiveLoopWithDelay 不会停止 - 所以我添加了一个新的私有变量 isLoopOnFlg 并且我想用它来停止递归函数 - 但我我不知道该怎么做。我试图通过在函数中添加一个新参数 keepLoopFlg 来停止该函数,如下所示:

...
private recursiveLoopWithDelay(loopFn: any, delay: number) {
    let stamp = Date.now();

    // Added a new param `keepLoopFlg` but it's not changed when `StopLoop()` is called
    function _loop(keepLoopFlg: boolean) {
        if (keepLoopFlg && Date.now() - stamp >= delay) {
            loopFn();
            stamp = Date.now();
        }

        window.requestAnimationFrame(_loop.bind(this, this.isLoopOnFlg)); // Used `.bind(...)`
    }

    window.requestAnimationFrame(_loop.bind(this, this.isLoopOnFlg));
}
...

但是上面的代码不会做我想要的 - 当调用 StopLoop() 时,递归函数仍然继续(内存泄漏)。 我很想学习如何使用当前结构停止递归函数并防止内存泄漏。请赐教!

首先,它并不是真正的递归,因为它在事件循环中对回调进行排队,而不是直接调用回调。因此,您不必担心 运行 调用堆栈内存不足。

要停止调用 requestAnimationFrame,您只需不调用它即可。问题是,你想什么时候停止调用它?如果您要为其他人提供实用功能,通常让他们决定何时“取消订阅”或停止更新。

private recursiveLoopWithDelay(loopFn: any, delay: number) {
    const self = this;
    let stamp = Date.now();

    function _loop() {
        // If we aren't looping anymore, just exit the code.
        // Don't requeue requestAnimationFrame
        if (!self.isLoopOn) {
            return;
        }

        if (Date.now() - stamp >= delay) {
            loopFn();
            stamp = Date.now();
        }

        window.requestAnimationFrame(_loop);
    }

    window.requestAnimationFrame(_loop);
}

您也可以像我在此处所做的那样使用词法作用域来跳过绑定。将 this 存储在我可以随时查找的变量 self 中。