Does A-Frame automatically remove global event listeners when an entity is removed from the scene?
0 reputation · 11 Aug 2025, 05:17 UTC
0 reputation · 11 Aug 2025, 05:17 UTC
This question concerns an A-Frame component that attaches event listeners to window and document during its init handler to track pointer and resize events across the full page.
The component is attached to entities that are frequently created and removed from the scene at runtime. A-Frame documents the remove lifecycle hook as the cleanup mechanism, but it is unclear whether the framework automatically detaches listeners bound to global objects when an entity is removed, or whether the component author must implement remove and call removeEventListener manually.
If global listeners persist after removal, the entity and its component may remain reachable and prevent garbage collection. It is also unclear whether this behavior differs across A-Frame 1.x releases.
Does A-Frame automatically remove window and document event listeners when an entity is removed from the scene? If not, is implementing the remove lifecycle hook the only reliable way to detach global listeners and avoid retained component memory?
34775 reputation · 11 Aug 2025, 10:39 UTC
No. A-Frame does not automatically remove event listeners attached to window, document, or any other global object when an entity is removed from the scene. The framework only invokes the component's remove lifecycle hook; it does not track or clean up listeners that the component registered on global targets.
A-Frame's entity-component system manages component lifecycle hooks (init, update, remove, etc.) but has no visibility into what a component does inside those hooks. When you call window.addEventListener('resize', handler) in init, the browser holds a reference to handler. Unless you explicitly call removeEventListener with the exact same function reference, that listener—and the component instance captured in its closure—remains reachable and blocks garbage collection.
Implement the remove hook and detach every global listener you added:
AFRAME.registerComponent('track-pointer', {
init: function () {
// Bind once so the same reference can be removed later
this.onResize = this.onResize.bind(this);
this.onPointerMove = this.onPointerMove.bind(this);
window.addEventListener('resize', this.onResize);
document.addEventListener('pointermove', this.onPointerMove);
},
remove: function () {
window.removeEventListener('resize', this.onResize);
document.removeEventListener('pointermove', this.onPointerMove);
},
onResize: function () { /* ... */ },
onPointerMove: function () { /* ... */ }
});
Key rules:
this.onResize) so the identical reference is available in remove.addEventListener if you need to remove them later.update adds listeners, clean up the previous set first to avoid duplicates.entity.parentNode.removeChild(entity).resize or pointermove event.console.log in the handler).window and verify the listener is gone.This behavior has been stable across all A-Frame 1.x releases (1.0 through 1.6+). No minor version introduced automatic global listener cleanup. The documented pattern above remains the only reliable approach.
If your component adds listeners in update (which can run multiple times), share the update logic. That changes whether you need an idempotent guard or a pre-cleanup step before re-registering.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.