[WEB] 느림의 미학 - Debounce, Throttle

느려터진 웹사이트는 왜 느릴까

프론트엔드 시점에서 웹사이트를 느리게 만드는 상황은 돌이켜봤을 때 이 정도가 생각난다.

  • 네트워크 지연 - 아무리 비동기 처리를 한다고 해도 로딩이 길면 어쩔 수 없다.
  • 불필요한 리렌더링 - <tr> 하나 추가할 때마다 수천 줄이 담긴 테이블 전체가 리렌더링 된다거나..?
  • 무거운 이벤트 핸들러 - scroll, resize, keyup을 할 때마다 네트워크가 호출된다면..

이 외에도 수많은 상황이 존재하겠지만, 이번 글에서는 마지막으로 언급한 무거운 이벤트 핸들러를 처리하기 위한 방법에 대해 다루려고 한다.

가장 확실한 방법 : 이벤트 핸들러 가볍게 만들기

당연하게도 쓸데없이 무거운 이벤트 핸들러를 가지고 있는 상황이라면
불필요한 로직을 핸들러 밖으로 옮기고 다음 단계를 논하는 게 맞을 것이다.

제목에 있는 Debounce, Throttle는 어쩔 수 없이 무거운 이벤트 핸들러를 처리하기 위함이라는 것부터 생각하자.

어쩔 수 없이 무거운 이벤트 핸들러 예시

아마 다들 슬랙, 페이스북, 아이메시지 등의 메신저를 써봤다면
'상대방이 입력 중'인 상태를 한 번씩은 본 경험이 있을 것이다.

이렇게 상대방을 쫄깃하게 만드는 기능을 구현하기 위해서는
키보드를 누를 때마다 불가피하게 네트워크를 통해 아직 입력 중이라는 정보를 전달해야 한다.

$input.addEventListener('keyup', e => {
  // 아직 입력 중임을 알리기 위한 네트워크 요청
});

만약 "개발자 살려" 라는 메시지를 보낸다면,
띄어쓰기 포함 13번의 네트워크 요청이 가게 된다.
(ㄱㅐㅂㅏㄹㅈㅏ ㅅㅏㄹㄹㅕ)

이 상황이 어쩔 수 없이 무거운 이벤트 핸들러의 대표적인 예시이다.

지금은 키보드 이벤트를 예시로 들었지만,
scroll/resize/mousedown 등 다양한 케이스에 대입해서 생각해볼 수 있다.

Debounce, Throttle

Debounce와 Throttle은 이러한 상황에서 타협을 제시하는 기법인데,
매 이벤트마다 호출하지 말고 적당히 천천히 실행하자는 것이 주요 컨셉이다.

둘의 공통점은 매번 동작을 실행하지 않는다는 점이고,
차이점은 다 끝나고(끝났다고 판단됐을 때) 실행하느냐 (debounce), 중간에 주기적으로 실행하느냐 (throttle) 이다.

아무튼 Debounce와 Throttle을 의인화하자면 다음과 같다.

(Debounce) 다 끝났으면 이제 처리해도 될까? 아, 안끝났구나.. 마저 해!

마지막 이벤트 이후로 (예를 들어) 500ms가 지나도 다음 이벤트가 발생하지 않으면 동작을 실행하는 식이다.

이 경우, 500ms 간격 안에서 이벤트가 계속 들어오면 단 한번도 동작이 실행되지 않는다.

(Throttle) 지금까지 된 건 일단 가져가고, 이따가 또 가지러 올게

이벤트가 계속 들어오더라도 매번 실행하지 않고 (예를 들어) 500ms 간격으로 동작을 실행한다.

이 경우, 500ms 간격 안에서 이벤트가 계속 들어오더라도 주기적으로 동작은 실행된다.

마무리

여기는 TIL이기도 하고 참고자료에 코드와 함께 설명은 잘 되어 있으니,
앞으로도 개념의 필요성과 이해하기 쉬운 요약 정도로 종종 찾아오도록 하겠습니다!
(꾸준히 오래 블로그하려면 페이스 조절이 중요하니까..ㅎ)

참고자료

https://www.zerocho.com/category/JavaScript/post/59a8e9cb15ac0000182794fa
https://pks2974.medium.com/throttle-와-debounce-개념-정리하기-2335a9c426ff
https://webclub.tistory.com/607

좋은 웹페이지 즐겨찾기