问题描述
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
中。