
โaddEventListenerโ์ ์ด๋ฒคํธ ํธ๋ค๋ฌ์ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ
โaddEventListenerโ์ ์ด๋ฒคํธ ํธ๋ค๋ฌ์ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ ๊ด๋ จ
์น ๊ฐ๋ฐ์์ DOM ์ด๋ฒคํธ๋ ๋น ์ง ์ ์๋ ํ์ ์์์
๋๋ค. ํด๋ฆญ, ํค๋ณด๋ ์
๋ ฅ, ๋ง์ฐ์ค ์ด๋ ๋ฑ ๋๋ถ๋ถ์ ์ฌ์ฉ์ ์ํธ์์ฉ์ addEventListener()
๋ฅผ ํตํด ๊ฐ์งํ๊ณ ์ฒ๋ฆฌํ๊ฒ ๋์ฃ . ์ด ๋ฉ์๋๋ ์๋ฐ์คํฌ๋ฆฝํธ์์ ์ด๋ฒคํธ๋ฅผ ๋ฑ๋กํ๋ ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ ๋ฐฉ์์ผ๋ก, ๊ฑฐ์ ๋ชจ๋ UI์์ ์ฌ์ฉ๋ฉ๋๋ค.
ํ์ง๋ง ์์ฃผ ์ฐ์ด๋ ๋งํผ, ๊ทธ๋งํผ ์ฝ๊ฒ ๊ฐ๊ณผ๋๋ ๋ฌธ์ ๊ฐ ์์ต๋๋ค. ๋ฐ๋ก โ๋ฉ๋ชจ๋ฆฌ ๋์(memory leak)โ์ ๋๋ค. ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ์๋ชป ๊ด๋ฆฌํ๋ฉด ๋ฉ๋ชจ๋ฆฌ์ ๋ถํ์ํ ์ฐธ์กฐ๊ฐ ๊ณ์ ๋จ๊ฒ ๋๊ณ , ์ด๋ก ์ธํด ๋ธ๋ผ์ฐ์ ์ฑ๋ฅ์ด ์ ์ ์ ํ๋๋ ์ํฉ์ด ๋ฐ์ํ ์ ์์ต๋๋ค. ํนํ React๋ Vue์ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ, ํ๋ ์์ํฌ์ ์ถ์ํ ์์ด ์ง์ DOM์ ๋ค๋ฃจ๊ฑฐ๋, ์๋ํํฐ ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ ๋ ์ด๋ฐ ๋ฌธ์ ๊ฐ ๋์ฑ ๋๋ ทํ๊ฒ ๋ํ๋ฉ๋๋ค.
์ด๋ฒ ๊ธ์์๋ addEventListener
๊ฐ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ์ ์ด๋ค ์ฐ๊ด์ด ์๋์ง, ์ฐ๋ฆฌ๊ฐ ํํ ์ ์ง๋ฅด๋ ์ค์๋ ๋ฌด์์ธ์ง, ๊ทธ๋ฆฌ๊ณ ์ค๋ฌด์์ ์ด๋ป๊ฒ ์ด๋ฅผ ๋ฐฉ์งํ ์ ์๋์ง๋ฅผ ์ค์ ์ฝ๋์ ํจ๊ป ์์ธํ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
์ด๋ฒคํธ ํธ๋ค๋ฌ ๋ฑ๋ก/์ ๊ฑฐ์ ์ค์์ฑ
์๋ฐ์คํฌ๋ฆฝํธ์์ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ ๋จ์ํ ์ฝ๋ฐฑ ํจ์๊ฐ ์๋๋๋ค. addEventListener()
๋ก ๋ฑ๋กํ๋ ์๊ฐ๋ถํฐ ๋ธ๋ผ์ฐ์ ๋ ํด๋น ํจ์๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ์ ์งํฉ๋๋ค. ์ด๋ฒคํธ๊ฐ ์ค์ ๋ก ๋ฐ์ํ๋ ๋ง๋ , ํธ๋ค๋ฌ๋ ๊ณ์ ๋ฉ๋ชจ๋ฆฌ์ ๋จ์์๋ ์ํ์ฃ . ์ด ์์ฒด๋ ๋ฌธ์ ๊ฐ ๋์ง ์์ง๋ง, ํธ๋ค๋ฌ ๋ด๋ถ์์ ํด๋ก์ ๋ฅผ ํตํด ์ธ๋ถ ๋ณ์๋ฅผ ์ฐธ์กฐํ๊ณ ์๋ค๋ฉด ์ํฉ์ ๋ฌ๋ผ์ง๋๋ค. ์๋ ์์ ๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
function setup() {
const largeData = new Array(1000000).fill("????");
document.getElementById("btn").addEventListener("click", () => {
console.log(largeData[0]);
});
}
์ด ์ฝ๋์์ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ largeData
๋ฅผ ์ฐธ์กฐํ๊ณ ์๊ธฐ ๋๋ฌธ์, ๋ธ๋ผ์ฐ์ ๋ ํด๋น ๋ฐ์ดํฐ๋ฅผ ๋ฉ๋ชจ๋ฆฌ์์ ์๊ฑฐํ์ง ๋ชปํฉ๋๋ค. setup()
ํจ์๋ ์ข
๋ฃ๋์์ง๋ง, largeData๋ ์ฌ์ ํ ์ด๋ฒคํธ ํธ๋ค๋ฌ ๋ด๋ถ์์ ์ ๊ทผ ๊ฐ๋ฅํ ์ํ์
๋๋ค.

์ด๋ฐ ๊ตฌ์กฐ๋ ์ฑ๊ธ ํ์ด์ง ์ ํ๋ฆฌ์ผ์ด์ (SPA)์ฒ๋ผ ํ ๋ฒ ๋ก๋๋ ํ ๊ณ์ ๋์ํ๋ ์ฑ์์ ํนํ ์์ฃผ ๋ฐ์ํฉ๋๋ค. ํ์ด์ง ์ ํ์ด ๋ฐ๋ณต๋๊ณ , ์ด๋ฒคํธ๊ฐ ๋์ ๋๋ฉด ์ ์ฒด ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ด ์ ์ฐจ ์ฆ๊ฐํ๊ฒ ๋ฉ๋๋ค.
removeEventListener
๋ ์ ํญ์ ์๋ํ์ง ์์๊น?
๋ง์ ๊ฐ๋ฐ์๋ค์ด ์ฐฉ๊ฐํ๋ ๋ถ๋ถ์ด ๋ฐ๋ก ์ด ์ง์ ์
๋๋ค. ์ด๋ฒคํธ๋ฅผ ์ ๊ฑฐํ๋ ค๊ณ removeEventListener()
๋ฅผ ํธ์ถํ๋๋ฐ, ์ฌ์ ํ ์ด๋ฒคํธ๊ฐ ์ด์์๋ ๊ฒฝํ์ ํด๋ณด์ ์ ์์ ๊ฒ๋๋ค. ์ด๊ฑด ๋ฒ๊ทธ๊ฐ ์๋๋ผ ํจ์ ์ฐธ์กฐ์ ๋ํ ์๋ฐ์คํฌ๋ฆฝํธ์ ๊ธฐ๋ณธ ๋์ ๋๋ฌธ์ธ๋ฐ์, ๋ค์ ์ฝ๋๋ฅผ ํตํด ์ดํด๋ณด๊ฒ ์ต๋๋ค.
1. removeEventListener
์ฌ์ฉ๋ฒ
element.addEventListener("click", () => console.log("clicked"));
element.removeEventListener("click", () => console.log("clicked")); // ์ ๊ฑฐ ์ ๋จ
์ธ๋ป ๋ณด๊ธฐ์ ๋์ผํ ์ฝ๋์ง๋ง, ์ด ๋ ํ์ดํ ํจ์๋ ์๋ก ๋ค๋ฅธ ๋ฉ๋ชจ๋ฆฌ ์ฃผ์๋ฅผ ๊ฐ์ง ์ ํ ๋ค๋ฅธ ํจ์์
๋๋ค. ์๋ฐ์คํฌ๋ฆฝํธ์์ ํจ์๋ ์ผ๊ธ ๊ฐ์ฒด์ด๋ฏ๋ก, ๋์ผํ ์ฝ๋๋ผ๋ ์๋ก์ด ํจ์ ๊ฐ์ฒด๊ฐ ์์ฑ๋ฉ๋๋ค. ๊ฒฐ๊ตญ removeEventListener
๋ ์ฒ์์ ๋ฑ๋กํ ํจ์์ ์ผ์นํ์ง ์๋ ์ฐธ์กฐ๋ฅผ ์ ๋ฌ๋ฐ๊ฒ ๋๊ณ , ํธ๋ค๋ฌ๋ ์ ๊ฑฐ๋์ง ์์ต๋๋ค. ์ด ๋ฌธ์ ๋ ๋ค์๊ณผ ๊ฐ์ด ๋ช
์์ ์ธ ํจ์ ์ฐธ์กฐ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ผ๋ก ํด๊ฒฐํ ์ ์์ต๋๋ค.
function handleClick() {
console.log("clicked");
}
element.addEventListener("click", handleClick);
element.removeEventListener("click", handleClick); // ์ ์ ์๋
์ค๋ฌด์์๋ ์ด๋ฒคํธ ๋ฑ๋ก๊ณผ ํด์ ๊ฐ ์๋ก ๋ค๋ฅธ ์์ ์์ ์ด๋ค์ง๊ธฐ ๋๋ฌธ์, ์ต๋ช
ํจ์๋ณด๋ค๋ ์ด๋ฆ์ด ์๋ ํจ์๋, ๋ณ์์ ์ ์ฅ๋ ํจ์๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์์ ํฉ๋๋ค. ๋์๊ฐ ์ฌ๋ฌ ํธ๋ค๋ฌ๋ฅผ ์ฒด๊ณ์ ์ผ๋ก ๊ด๋ฆฌํ๊ธฐ ์ํด Map
์ด๋ WeakMap
์ ํ์ฉํ๋ ๋ฐฉ์๋ ์์ฃผ ์ฌ์ฉ๋ฉ๋๋ค.
const handlerMap = new Map();
function addHandler(el, key, fn) {
el.addEventListener("click", fn);
handlerMap.set(key, fn);
}
function removeHandler(el, key) {
const fn = handlerMap.get(key);
if (fn) {
el.removeEventListener("click", fn);
handlerMap.delete(key);
}
}
addHandler(button, "confirm", () => console.log("ํ์ธ ํด๋ฆญ"));
removeHandler(button, "confirm"); // ์ ํํ ์ฐธ์กฐ๋ก ์ ๊ฑฐ๋จ
์ด ๊ตฌ์กฐ๋ ํนํ ์ปดํฌ๋ํธ ๊ธฐ๋ฐ UI๋ ์ปค์คํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ๋งค์ฐ ์ ์ฉํฉ๋๋ค. ์ด๋ฒคํธ๋ฅผ ๋ฑ๋กํ ๋๋ง๋ค ํจ์ ์ฐธ์กฐ๋ฅผ Map์ ์ ์ฅํด๋๋ฉด, ๋์ค์ ๋์ผํ ํค๋ก ์ ๊ทผํด ์ ํํ ํธ๋ค๋ฌ๋ฅผ ์ ๊ฑฐํ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
๋ฉ๋ชจ๋ฆฌ ๋์ ๋ฐฉ์ง ํ
์ด๋ฒคํธ ํธ๋ค๋ฌ์ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํ ์ฒซ๊ฑธ์์, ์ด๋ฒคํธ๋ฅผ ๋ฑ๋กํ๋ ์๊ฐ๋ถํฐ โ์ธ์ ํด์ ํ ์งโ๋ฅผ ํจ๊ป ๊ณ ๋ฏผํ๋ ๊ฒ์ ๋๋ค. ์๋ฌด๋ฆฌ ์งง์ ์ฝ๋๋ผ๋, ์ต๋ช ํจ์๋ก ๋ฑ๋ก๋ ํธ๋ค๋ฌ๋ ์ ํํ ์ ๊ฑฐํ๊ธฐ ์ด๋ ต์ต๋๋ค. ๊ฐ๋ฅํ ๊ฒฝ์ฐ์๋ ํจ์ ์ ์ธ๋ฌธ์ด๋ ํ์ดํ ํจ์๋ฅผ ๋ณ์์ ์ ์ฅํด๋๊ณ ์ฌ์ฌ์ฉํ๋ ๊ฒ์ด ๋ฐ๋์งํฉ๋๋ค.
๋ํ DOM ์์๊ฐ ์ญ์ ๋์๋ค๊ณ ํด์ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ ํจ๊ป ์ ๊ฑฐ๋๋ ๊ฒ์ ์๋๋๋ค. ๋ค์๊ณผ ๊ฐ์ ์ฝ๋๋ฅผ ๋ณด๋ฉด ๊ทธ ์ฐจ์ด๋ฅผ ์ฝ๊ฒ ์ดํดํ ์ ์์ต๋๋ค.
const handler = () => console.log("clicked");
button.addEventListener("click", handler);
button.remove(); // DOM์์ ์ ๊ฑฐ๋จ
// ํ์ง๋ง ๋ฉ๋ชจ๋ฆฌ์๋ ์ฌ์ ํ handler๊ฐ ๋จ์ ์์
์ด๋ฌํ ๊ฒฝ์ฐ, ํธ๋ค๋ฌ๋ ์ฌ์ ํ ๋ฉ๋ชจ๋ฆฌ์ ๋จ์ ์์ผ๋ฉฐ, ์ฐธ์กฐ๊ฐ ์กด์ฌํ๊ธฐ ๋๋ฌธ์ GC๊ฐ ํ์ํ์ง ๋ชปํ๊ฒ ๋ฉ๋๋ค. ๋ฐ๋ผ์ removeEventListener
๋ฅผ ๋ช
์์ ์ผ๋ก ํธ์ถํด ์ฃผ๋ ๊ฒ์ด ์์ ํฉ๋๋ค.
๋คํํ๋ ์๋ฐ์คํฌ๋ฆฝํธ๋ once: true
๋ผ๋ ์ต์
์ ์ ๊ณตํ๋๋ฐ์. ์ด ์ต์
์ ์ค์ ํ๋ฉด ์ด๋ฒคํธ๊ฐ ํ ๋ฒ๋ง ์คํ๋๊ณ ์๋์ผ๋ก ์ ๊ฑฐ๋๊ธฐ ๋๋ฌธ์, ์ผํ์ฑ ์ด๋ฒคํธ์๋ ์ ์ฉํ ํจํด์ด ๋ฉ๋๋ค.
button.addEventListener("click", handleClick, { once: true });
์ถ๊ฐ๋ก WeakMap
์ ์ฌ์ฉํ๋ฉด DOM ์์๊ฐ GC์ ์ํด ์๊ฑฐ๋ ๋, ๊ทธ์ ์ฐ๊ฒฐ๋ ํธ๋ค๋ฌ๋ ์์ฐ์ค๋ฝ๊ฒ ๋ฉ๋ชจ๋ฆฌ์์ ํด์ ๋๋ ๊ตฌ์กฐ๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.
const handlerMap = new WeakMap();
function addHandler(el, fn) {
handlerMap.set(el, fn);
el.addEventListener("click", fn);
}
function removeHandler(el) {
const fn = handlerMap.get(el);
if (fn) el.removeEventListener("click", fn);
}
๋๋ฒ๊น ์ฑ๋ฅ ๋ชจ๋ํฐ๋ง
์ค์ ๋ก ๋ฉ๋ชจ๋ฆฌ ๋์๊ฐ ๋ฐ์ํ๋์ง ํ์ธํ๋ ค๋ฉด ๋ธ๋ผ์ฐ์ ์ ๊ฐ๋ฐ์ ๋๊ตฌ๋ฅผ ํ์ฉํด์ผ ํฉ๋๋ค. Chrome์ Memory ํญ์์ ํ ์ค๋ ์ท์ ๋น๊ตํ๊ฑฐ๋, Performance Monitor๋ฅผ ํตํด Event Listeners ์๋ฅผ ์ถ์ ํ๋ฉด ์ ์ฉํ ํํธ๋ฅผ ์ป์ ์ ์์ต๋๋ค.

ํนํ Detached DOM Tree์ฒ๋ผ, DOM์์ ์ ๊ฑฐ๋์์ง๋ง, ์ฌ์ ํ ๋ฉ๋ชจ๋ฆฌ์ ๋จ์์๋ ๋ ธ๋๋ฅผ ๋ฐ๊ฒฌํ๋ค๋ฉด ์์ฌํด ๋ณผ ํ์๊ฐ ์์ต๋๋ค.

๋ํ SPA ํ๊ฒฝ์์ ๋ผ์ฐํ ์ด ๋ฐ๋ณต๋๋ ์ฑ์ด๋ผ๋ฉด, ๋ผ์ฐํ ์ ์ ๊ธฐ์กด ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ๋ชจ๋ ์ ๊ฑฐํ๋ ๋ฃจํด์ ์ถ๊ฐํด ๋๋ ๊ฒ๋ ์ข์ ์๋ฐฉ์ฑ ์ ๋๋ค.
๋ง์น๋ฉฐ
addEventListener()
๋ ์ฐ๋ฆฌ๊ฐ ๋๋ฌด๋ ์์ฃผ ์ฌ์ฉํ๋ ๋ฉ์๋์
๋๋ค. ํ์ง๋ง ๊ทธ๋งํผ ๋ฐฉ์ฌํ๊ธฐ ์ฌ์ด ๋๊ตฌ์ด๊ธฐ๋ ํ์ฃ . ํธ๋ค๋ฌ ํ๋์ฏค์ด์ผ, DOM ํ๋์ฏค์ด์ผ ํ๋ ์๊ฐ์ ๊ฒฐ๊ตญ ์ฅ๊ธฐ์ ์ธ ์ฑ๋ฅ ์ ํ์ ์ง๊ฒฐ๋ฉ๋๋ค.
์ค์ํ ๊ฒ์ ์ต๊ด์ ๋๋ค. ์ด๋ฒคํธ๋ฅผ ๋ฑ๋กํ ๋๋ โ์ธ์ , ์ด๋ค ๋ฐฉ์์ผ๋ก ํด์ ํ ๊ฒ์ธ์งโ๋ฅผ ํญ์ ํจ๊ป ๊ณ ๋ฏผํด์ผ ํฉ๋๋ค. ๋ช ์์ ์ธ ์ฐธ์กฐ ๊ด๋ฆฌ, ํด์ ๋ก์ง์ ์ค๊ณ, ์ ์ ํ ๋๊ตฌ์ ํ์ฉ์ด์ผ๋ง๋ก ํด๋ฆฐํ UI, ์ ์ง๋ณด์ ๊ฐ๋ฅํ ์ฝ๋์ ๊ธฐ๋ณธ์ด ๋ ์ ์์ต๋๋ค. ์ง๊ธ ์ด ์๊ฐ์๋ ๋ธ๋ผ์ฐ์ ๋ฉ๋ชจ๋ฆฌ ์ด๋๊ฐ์๋ ์ ๊ฑฐ๋์ง ์์ ์ด๋ฒคํธ ํธ๋ค๋ฌ๊ฐ ๋จ์ ์์์ง๋ ๋ชจ๋ฆ ๋๋ค. ์ด ๊ธ์ ์ฝ๊ณ ๋์, ํ๋์ฉ ์ง์๋ณด๋๋ก ํฉ์๋ค.