JavaScript

js/listener-cleanup

Listeners, timers and observers a view starts are removed when it goes away; one AbortController signal can end them all.

moderatemanualfe-javascript

Why

In a single-page app, a view that adds a resize listener, a setInterval or an IntersectionObserver and never removes it keeps running after navigation: memory grows, handlers fire twice after the view comes back, and they act on elements that no longer exist.

Fix

Create one AbortController per view or component, pass { signal } to every addEventListener and to fetch, and call abort() on teardown (the effect cleanup, onUnmounted, disconnectedCallback, DestroyRef.onDestroy). Clear timers with clearInterval and call disconnect() on observers in the same place.

Examples

// bad
connectedCallback() { window.addEventListener('resize', this.layout) }
// good
connectedCallback() {
  this.controller = new AbortController()
  window.addEventListener('resize', this.layout, { signal: this.controller.signal })
}
disconnectedCallback() { this.controller.abort() }

Sources

Facts

Id
js/listener-cleanup
Severity
moderate
Check
manual a person reviews it; the report lists it as a checklist
Applies to
jsx vue svelte astro html
Taught by the skill
fe-javascript JavaScript in the browser
Since version
0.1.0

Rule file on GitHub

Read it in the terminal

npx github:dawidolko/frontend-skills explain js/listener-cleanup