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
- 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.
- Press a key, for example
a. Both counters report it. - Click "Remove both counters" and press
aagain. - Only
leaky counter: 2appears: the removed<leaky-counter>still listens and keeps its state, the removed<clean-counter>does not.
console.log() and errors on this page, the same text as in the developer toolsleaky 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>