JavaScript Event Flow

성훈·2021년 7월 6일
0

OiMW

목록 보기
6/12
post-thumbnail

JavaScript Event Flow

이벤트 플로우란?

이벤트 플로우, 이벤트 흐름이란 무엇일까.

평범하게 이런 html 코드가 있다고 가정해보자.

<html>
  <body>
    <div>Click Here!</div>
  </body>
</html>

상술한 코드에서 div요소가 클릭 되었을때(onclick)를 감지해서 함수가 실행되도록 코드를 짜고 div 요소를 클릭했을때, 만약 div의 상위 요소인 bodyhtml 등에도 클릭 이벤트 핸들러가 짜여 있다면 bodyhtml의 클릭을 감지하는 이벤트 핸들러는 어떻게 될까?

정답은 '사이좋게 실행된다.' 이다.

여기서 이벤트를 직접 실행시킨 div가 이벤트의 원인이되는 것이고, bodyhtml은 이벤트에 탑승했다고 한다.

그런데 우애 좋은 형제 사이에도 찬물 마실땐 위 아래가 있듯, 사이좋게 실행되더라도 먼저 실행되는 윗 놈(이벤트)이 있을 것이다.

이 이벤트들이 실행되는 순서를 사람들은 Event Flow라고 부른다.

.target vs .currentTarget

이벤트 플로우를 알아보기 전에 targetcurrentTarget이 어떻게 다른지부터 짚고 가자.

우선 개괄적으로 한번 짚고 지나가자면 target은 시작점을 뜻하고 currentTarget 은 지금 실행 중인 이벤트가 어디서 실행중인지를 의미한다.

이렇게만 말하면 느낌이 바로 안오니 위에서 만들어 놓은 HTML을 보면서 이야기 해보자

<html>
  <body>
    <div>Click Here!</div>
  </body>
</html>

여기서 우리는 모든 요소에 클릭 이벤트 핸들러를 짜 놓았다.
여기서 div를 클릭해 이벤트가 발생했을때,
div 이벤트 핸들러에서는 targetdiv가 되고 currentTarget 역시 div가 된다.

그럼 body 이벤트 핸들러에서는 어떻게 될까?
target이벤트의 시작점div가 되고 currentTarget은 누가 어디서 이벤트를 실행했던, 실행된건 body에 연결된 이벤트 핸들러이니 body가 된다.
html의 경우도 targetdiv, targetCurrenthtml이 된다.

이벤트의 흐름

우선 어디에서든지 이벤트가 발생하면 root에서 가까운 순으로 이벤트가 실행된다.

<html>
  <body>
    <div>Click Here!</div>
  </body>
</html>

우리가 예제로 삼고있는 코드에서는 html가장 루트에 가까우니 html을 요소로 가지는 이벤트 핸들러가 가장 먼저 실행이 되게 되는 것이다.

그 다음엔 body 에 연결된 이벤트 핸들러 그리고 나서 드디어 div에 연결된 이벤트 핸들러가 실행되게 된다.

여기서 div에 연결되기 전까지의 단계를 Capture Phase 라고 하고 div에 연결된 이벤트 핸들러가 실행되는 단계를 Target Phase라고 한다.

targetdiv에 연결된 이벤트 핸들러가 실행되고 나면 다시 역순으로 root로 돌아가며 이벤트 핸들러들을 실행시킨다.

이 경우 bodyhtml에 연결된 이벤트 핸들러들이 body, html 순서로 다시 한번 실행되는 것이다.

이 단계를 Bubble Phase 라고 하며 이 Bubble Phase를 끝으로 이벤트는 종료된다.

이벤트 플로우Capture Phase -> Target Phase -> Bubble Phase 순으로 이어진다.

이걸 그림으로 나타내면 다음과 같다.

필체가 상당히 더럽다

선택하라

이 페이즈 대로 실행된다면 div 의 상위 요소에 연결된 이벤트 핸들러들은 두번씩 실행이 되고만다.

하지만 현명한 브라우저님은 이 상위 요소에 연결된 이벤트 핸들러들, 즉 targetcurrentTarget이 일치하지 않는 이벤트 핸들러들에 대해 한번씩 실행되게 제약을 걸고 Capture Phase에서 실행될 것인지 Bubble Phase에서 실행될 것 인지 선택하게 한다.

선택하는 방법은 닷 노테이션으로 이벤트 핸들러를 표현할 땐 사용할 수 없고 addEventListener 메소드를 사용해야한다.

addEventListener의 문법은 target.addEventListener(type, listener[, useCapture] 인데,
여기서 useCapture 자리에 불리언 타입을 인자로 받는데 여기에 true를 넣으면 Capture Phase에서 이벤트 핸들러가 실행되고 기본 값false를 넣으면 Bubble Phase에서 실행되게 된다.

즉, 따로 불리언 타입을 넣지 않으면 Bubble Phase에서 실행되기에 target의 이벤트 핸들러가 가장 먼저 실행되게 된다.

<html>
  <body>
    <div>Click Here!</div>
  </body>
</html>
let html = document.documentElement;
let body = document.body;
let div = document.querySelector('div');

html.addEventListener('click', function(){
  console.log('I\'m Html Event Handler!')
})
body.addEventListener('click', function(){
  console.log('I\'m Body Event Handler!')
})
div.addEventListener('click', function(){
  console.log('I\'m Div Event Handler!')
})

기본 값이 falseBubble Phase에 실행된 것을 볼 수 있다.

let html = document.documentElement;
let body = document.body;
let div = document.querySelector('div');

html.addEventListener('click', function(){
  console.log('I\'m Html Event Handler!')
})
body.addEventListener('click', function(){
  console.log('I\'m Body Event Handler!')
}, true)
div.addEventListener('click', function(){
  console.log('I\'m Div Event Handler!')
})

여기선 body에 연결된 이벤트 핸들러가 Capture Phase에 실행되었기 때문에 가장 먼저 실행된 것을 볼 수 있다.

정리

기본 값이 false로 받아 버블 페이즈로 실행되서 아마 크게 쓸일이 없을 것 같긴하지만, 미래에 이걸 정리 안해서 고생할 나를 위해 미리 정리한다.

오랜만에 TIL 빼고 OiMW에서 열심히 포스팅한 것 같은데 TIL에 적어놓은거 OiMW로 다시 정리할거 생각하면 머리가 아파온다.

도움 많이 받은 곳

김버그님 유튜브
정말 잘 봤습니다 이해 너무 잘 됐어요 🙏

https://developer.mozilla.org/

profile
어떻게 이걸 풀어낼 수 있을까

0개의 댓글