Skip to content

Commit 0e52393

Browse files
obiotclaude
andcommitted
Properly stop render loop on destroy() using context-based event removal
Application.destroy() now uses off(event, method, this) to cleanly unregister TICK, BLUR, and FOCUS listeners — leveraging the native context support added to EventEmitter. Extracted anonymous listeners into named methods (_tick, _onBlur, _onFocus) so they can be properly removed by function reference. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 4e6c74d commit 0e52393

1 file changed

Lines changed: 36 additions & 23 deletions

File tree

packages/melonjs/src/application/application.ts

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -345,28 +345,12 @@ export default class Application {
345345
on(STATE_RESUME, this.repaint, this);
346346
on(STAGE_RESET, this.reset, this);
347347
/* eslint-enable @typescript-eslint/unbound-method */
348-
on(TICK, (time: number) => {
349-
this.update(time);
350-
this.draw();
351-
});
352-
353-
on(BLUR, () => {
354-
if (this.stopOnBlur) {
355-
state.stop(true);
356-
}
357-
if (this.pauseOnBlur) {
358-
state.pause(true);
359-
}
360-
});
361-
362-
on(FOCUS, () => {
363-
if (this.stopOnBlur) {
364-
state.restart(true);
365-
}
366-
if (this.resumeOnFocus) {
367-
state.resume(true);
368-
}
369-
});
348+
// eslint-disable-next-line @typescript-eslint/unbound-method
349+
on(TICK, this._tick, this);
350+
// eslint-disable-next-line @typescript-eslint/unbound-method
351+
on(BLUR, this._onBlur, this);
352+
// eslint-disable-next-line @typescript-eslint/unbound-method
353+
on(FOCUS, this._onFocus, this);
370354
}
371355

372356
this.isInitialized = true;
@@ -476,8 +460,11 @@ export default class Application {
476460
* app.destroy();
477461
*/
478462
destroy(removeCanvas: boolean = true): void {
479-
// remove event listeners
463+
// stop the render loop and remove all event listeners
480464
/* eslint-disable @typescript-eslint/unbound-method */
465+
off(TICK, this._tick, this);
466+
off(BLUR, this._onBlur, this);
467+
off(FOCUS, this._onFocus, this);
481468
off(STATE_CHANGE, this.repaint, this);
482469
off(STATE_RESTART, this.repaint, this);
483470
off(STATE_RESUME, this.repaint, this);
@@ -507,6 +494,32 @@ export default class Application {
507494
this.isDirty = true;
508495
}
509496

497+
/** @ignore */
498+
_tick(time: number): void {
499+
this.update(time);
500+
this.draw();
501+
}
502+
503+
/** @ignore */
504+
_onBlur(): void {
505+
if (this.stopOnBlur) {
506+
state.stop(true);
507+
}
508+
if (this.pauseOnBlur) {
509+
state.pause(true);
510+
}
511+
}
512+
513+
/** @ignore */
514+
_onFocus(): void {
515+
if (this.stopOnBlur) {
516+
state.restart(true);
517+
}
518+
if (this.resumeOnFocus) {
519+
state.resume(true);
520+
}
521+
}
522+
510523
/**
511524
* update all objects related to this game active scene/stage
512525
* @param time - current timestamp as provided by the RAF callback

0 commit comments

Comments
 (0)