From 9104064e8c4f95fd20d94b48d535b63974742920 Mon Sep 17 00:00:00 2001 From: liuguiyuan <875079152@qq.com> Date: Wed, 8 Apr 2026 18:53:42 +0800 Subject: [PATCH] fix(mask): stop requestAnimationFrame loop on dispose to prevent memory leak The #moveCursorToTarget() method recursively schedules itself via requestAnimationFrame, creating a continuous animation loop for the AI cursor. However, dispose() only removes the DOM wrapper element without stopping this loop, causing: - CPU waste: rAF callback continues executing every frame (~60fps) after the mask is disposed, performing unnecessary calculations on a detached cursor element. - Resource leak: Each SimulatorMask instance creates an unrecoverable animation loop that persists for the lifetime of the page. - Console noise: style assignments to removed DOM nodes may produce browser warnings. Fix: Add a #disposed boolean flag, checked at the top of #moveCursorToTarget() to short-circuit the recursion. Set the flag to true in dispose() before removing DOM elements. Changes: - Add #disposed field (default false) - Guard #moveCursorToTarget() with early return when #disposed - Set #disposed = true in dispose() before cleanup --- packages/page-controller/src/mask/SimulatorMask.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/page-controller/src/mask/SimulatorMask.ts b/packages/page-controller/src/mask/SimulatorMask.ts index 41cbdb4..ec986cc 100644 --- a/packages/page-controller/src/mask/SimulatorMask.ts +++ b/packages/page-controller/src/mask/SimulatorMask.ts @@ -10,6 +10,8 @@ export class SimulatorMask extends EventTarget { wrapper = document.createElement('div') motion: Motion | null = null + #disposed = false + #cursor = document.createElement('div') #currentCursorX = 0 @@ -129,6 +131,7 @@ export class SimulatorMask extends EventTarget { } #moveCursorToTarget() { + if (this.#disposed) return const newX = this.#currentCursorX + (this.#targetCursorX - this.#currentCursorX) * 0.2 const newY = this.#currentCursorY + (this.#targetCursorY - this.#currentCursorY) * 0.2 @@ -200,6 +203,7 @@ export class SimulatorMask extends EventTarget { } dispose() { + this.#disposed = true console.log('dispose SimulatorMask') this.motion?.dispose() this.wrapper.remove()