skip to content
dz

Back to the article · Zurück zum Artikel (Deutsch)

Example 04: Listener on document: leaked or cleaned up

Rule 2: Don't dispatch events or listen on document in the constructor

Two counters count key presses with a listener on document. <leaky-counter> registers it in the constructor and never removes it, <clean-counter> registers in connectedCallback and unregisters in disconnectedCallback.

How to try it

  1. Open the console of the developer tools (F12, Cmd+Opt+I on a Mac). The "Console output" box on this page shows the same lines.
  2. Press a key, for example a. Both counters report it.
  3. Click "Remove both counters" and press a again.
  4. Only leaky counter: 2 appears: the removed <leaky-counter> still listens and keeps its state, the removed <clean-counter> does not.
Console output mirrored from console.log() and errors on this page, the same text as in the developer tools
Expected output what the lines above should say
leaky counter: 1
clean counter: 1
leaky counter: 2

Live example

Source

<button id="remove-counters" type="button">Remove both counters</button>

<leaky-counter></leaky-counter>
<clean-counter></clean-counter>

<script type="module">
	class LeakyCounter extends HTMLElement {
		#count = 0;

		constructor() {
			super();
			// Rule 2: registered in the constructor, never removed
			document.addEventListener('keydown', () => console.log('leaky counter:', ++this.#count));
		}
	}

	class CleanCounter extends HTMLElement {
		#count = 0;
		#onKey = () => console.log('clean counter:', ++this.#count);

		connectedCallback() {
			document.addEventListener('keydown', this.#onKey);
		}

		disconnectedCallback() {
			document.removeEventListener('keydown', this.#onKey);
		}
	}

	customElements.define('leaky-counter', LeakyCounter);
	customElements.define('clean-counter', CleanCounter);

	document.getElementById('remove-counters').addEventListener('click', () => {
		document.querySelector('leaky-counter').remove();
		document.querySelector('clean-counter').remove();
	});
</script>