#javascript #typescript #recursion #memory-leaks #requestanimationframe
#javascript #typescript #рекурсия #утечки памяти #requestanimationframe
Вопрос:
У меня есть класс с функцией рекурсивного цикла, подобной приведенной ниже:
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 amp;amp; 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()
вызове рекурсивная функция все еще продолжает работать (утечка памяти).
Я хотел бы узнать, как остановить рекурсивную функцию с текущей структурой и предотвратить утечку памяти. Пожалуйста, просветите меня!
Ответ №1:
Во-первых, это не совсем рекурсивно, поскольку он ставит обратный вызов в очередь в цикле событий, а не вызывает обратный вызов напрямую. Таким образом, вам не нужно беспокоиться о нехватке памяти в стеке вызовов.
Чтобы прекратить вызов 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
, которую я могу искать в любой момент.
Комментарии:
1. Ах, готя, ключи
self = this
и позицияisLoopOn
. Спасибо, что помогли мне!