Reputation: 5374
I have a class with the recursive loop function like the below:
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);
}
}
As you see, the function recursiveLoopWithDelay
won't be stopped - so I've added a new private variable isLoopOnFlg
and I want to use it to stop the recursive function - but I am not sure how to do it. I tried to stop the function by adding a new parameter keepLoopFlg
in the function like the below:
...
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));
}
...
But the above code won't do what I want - when StopLoop()
is called, the recursive function still keep going (memory leak).
I'd love to learn how to stop the recursive function with the current structure and to prevent memory leak. Please enlighten me!
Upvotes: 0
Views: 703
Reputation: 39992
First, it's not really recursive since it queues the callback on the event loop rather than calling the callback directly. So you don't have to worry about running out of memory on the call stack.
To stop calling requestAnimationFrame, you simply don't call it. The question is, when do you want to stop calling it? If you are providing a utility function for someone else, you usually let them dictate when to "unsubscribe" or stop the updates.
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);
}
You can also skip binding by using Lexical scope like I've done here. Storing this
in a variable self
that I can lookup at any point.
Upvotes: 2