[TIL] 프론트엔드 Day 20

📚 공부한 내용

1. Event

이벤트

이벤트는 주로 마우스를 클릭하거나 스크롤을 내리는 등 사용자의 동작에 의해서 발생한다. 우리는 DOM Element에 addEventListener를 사용해 특정 이벤트가 발생할 때, 어떻게 처리할 것인지 이벤트 핸들러를 등록할 수 있다. 하나의 Element에 여러개의 이벤트가 존재할 수 있으며, removeEventListener를 사용해 제거하는 것도 가능하다. 만약 핸들러가 등록된 element에 이벤트가 발생하면, 브라우저는 이벤트에 관련된 세부 내용들을 Event Object에 넣어 핸들러에 전달한다.

이벤트 페이즈

이벤트는 3개의 단계(Phase)를 거쳐서 생성되고 소멸한다.

  • Capturing Phase
    DOM tree의 최상위 요소부터 이벤트가 발생한 target element까지 전파되는 단계.

  • Target Phase
    이벤트가 실제 target element까지 전파되는 단계

  • Bubbling Phase
    이벤트가 target element에서 최상위 element까지 전파되는 단계
    (Capturing Phase와 역순)

아무런 옵션 없이 addEventListener를 사용했다면, 핸들러가 동작한는 단계는 Target Phase와 Bubbling Phase이다. 그리고 만약 capture 옵션이 true라면 Capturing Phase부터 핸들러가 동작한다.


위와 같이 3개의 <div> element가 중첩되어 있을 때, div3을 클릭해 이벤트가 발생한 상황을 가정하자. Capturing Phase에서는 div1 - div2 - div3 순서로 이벤트가 전파된다. 이벤트가 발생한 div3에서 Target Phase가 진행되고, 이후 Bubbling Phase에서 div3 - div2 - div1 순서로 이벤트가 전파된다.

이벤트 델리게이션

어떤 element에 이벤트가 발생할 때 실행하고 싶은 코드가 있다면 해당 element에 addEventListener를 사용하는 것이 일반적이다. 하지만 그러한 element가 수가 아주 많다면? 무분별하게 모든 element에 이벤트 핸들러를 할당하면 너무 많은 메모리를 사용하게 되고, 성능면에서도 효율적이지 않다. 이 상황에서 사용할 수 있는 패턴이 바로 이벤트 델리게이션 패턴이다.
이벤트 델리게이션 패턴은 이벤트 버블링을 이용한다. 이벤트 핸들러의 할당이 필요한 여러 element들을 상위 element로 감싸고, 이 상위 element에만 핸들러를 할당한다.

위와 같은 element 구조에서 <div> element에 이벤트 핸들러를 할당하면, 4개의 <button>에서 이벤트가 발생해도, 버블링에 의해서 <div>의 이벤트 핸들러가 동작한다. 또한 어떤 하위 element가 target이 되는지 Event Object의 target 프로퍼티에서 확인이 가능하다.

<div id="button-container">
  <button id="button1">Button1</button>
  <button id="button2">Button2</button>
  <button id="button3">Button3</button>
  <button id="button4">Button4</button>
</div>
const $div = document.querySelector('#button-container');

$div.addEventListener('click', (e) => {
  const $targetElement = e.target;
  if ($targetElement.id === "button1") {
	// do something
  } else if ($targetElement.id === "button2") {
    // do something
  } 
  ...
});

위의 코드는 이벤트 델리게이션을 사용한 예시이다. 이렇게 이벤트 델리게이션 패턴을 사용하면 여러개의 이벤트를 하나의 핸들러에서 처리하는 것이 가능하다.

이벤트 디바운스

이벤트 디바운스는 이벤트 핸들러의 동작을 조절하는 기법 중 하나이다. 동일한 이벤트가 짧은 간격으로 여러번 발생할 때, 일정 시간동안 이벤트의 처리를 미루고 일정 시간이 지나도 이벤트가 발생하지 않았다면 가장 마지막 이벤트에 대해서만 처리가 이뤄진다.

자동 저장 기능을 가진 문서 편집기를 구현한다고 생각해 보자. 문서의 내용이 바뀔 때마다 이벤트를 발생시켜 변경된 내용을 저장한다면 한 글자 입력할 때 마다 이벤트 핸들러가 동작한다. "안녕하세요" 같이 단순한 문자를 입력할 때도, 별도의 처리가 없을 경우 이벤트 핸들러는 12번 동작한다. 만약 저장이 API를 통해서 이루어 진다면 더더욱 큰 성능 저하가 일어날 것이다.

이벤트 디바운스는 setTimeoutclearTimeout을 이용해서 구현한다.

let timer = null;
const delay = 2000;
$element.addEventListener('change', (e) => {
	if(timer !== null) {
		clearTimeout(timer);
    }
  	time = setTimeout(() => {
    	//do something
    }, delay)
});

이벤트가 발생하면 setTimeout이 실행되며, 타이머가 delay에 해당하는 시간이 지났을 때 실행하고자 하는 내용의 코드가 동작할 것이다. 하지만 정해놓은 시간이 지나기 전에 동일한 이벤트가 발생한다면 clearTimeout에 의해서 이전의 타이머는 취소되고 새로운 타이머가 처음부터 시작한다.


📝 더 공부할 것

  • dispatchEvent와 커스텀 이벤트
  • 이벤트 쓰로틀

🤔 느낀점

노션 클로닝 프로젝트 주간이라 TIL을 꾸준히 적지 못하고있다. 프로젝트에 대해서도 생각할 일이 많아지고 필요한 부분만 찾아서 쓰다보니 공부한 내용에 대해서 정리가 어렵다. 다시 마음을 다잡고 이벤트부터 찬찬히 정리를 해봤는데, 적지 못한 내용이 대부분일 정도로 그 범위가 너무 넓고 깊다. 역시 공부는 끝이 없다.😅


Reference

  1. 프로그래머스 프론트엔드 데브코스

  2. JAVASCRIPT.INFO, 브라우저 이벤트 소개
    https://ko.javascript.info/introduction-browser-events

좋은 웹페이지 즐겨찾기