쓰로틀링과 디바운싱 알아보기

gydotb·2025년 1월 12일
0

독감자스터디

목록 보기
2/5

해당 주제 선정 이유

프로젝트에서 반응형 적용 가능한 캘린더를 제작하는 과정에서 resizeObserver를 이용할 일이 있었다. 최적화 방법을 찾다가 쓰로틀링과 디바운싱이라는 개념을 알게 되어 정리해보고자 해당 주제를 선정하게 되었다.

왜 사용할까?

JS에서 이벤트를 다루다보면 무수히 많은 이벤트가 발생하는 경우를 확인할 수 있다. 이런 무의미한 이벤트 호출을 방지하고, 최적화시키기 위해 쓰로틀링과 디바운싱이라는 개념을 이용한다.

이벤트 예시로는 scroll, resize, input, mousemove 등이 있을 수 있다.

개념 알아보기

쓰로틀링과 디바운싱에 대해 설명하고,

🐶 쓰로틀링이란?

일정 시간 내 이벤트를 한 번만 실행하도록 제어하는 것으로 보통 마지막 함수 호출 이후 일정 시간 후 함수를 호출할 수 있도록 제어한다.

쓰로틀은 짧은 시간 간격으로 연속해서 발생하는 이벤트를 그룹화해서 일정 시간 단위로 이벤트 핸들러가 호출되도록 호출 주기를 만든다!

사용 방법

window.addEventListener('input', throttle(function(e) {
    console.log(e.target.value);
}, 200));

function throttle(func, delay) {
    let timer;
    return function() {
        const args = arguments;
        clearTimeout(timer);
        timer = setTimeout(() => {
            func.apply(this, args);
        }, delay);
    }
}

간단한 input 예제로, 0.2초에 한 번 함수가 실행되도록 만든 경우이다.

사용 사례

주로 scroll 혹은 무한 스크롤 UI 구현 등에서 사용한다.

🐱 디바운싱이란?

한 행위를 여러 번 반복할 시, 즉 동일한 이벤트를 여러번 요청할 시에 마지막 행위 이후 특정 시간이 지나야 콜백을 호출할 수 있도록 하는 방식이다,

사용 방법

window.addEventListener('input', debounce(function(e) {
    console.log(e.target.value);
}, 200));

function debounce(func, delay) {
    let timer;
    return function() {
        const args = arguments;
        clearTimeout(timer);
        timer = setTimeout(() => {
            func.apply(this, args);
        }, delay);
    }
}

위의 쓰로틀링과 동일한 예제이나 debounce를 적용한 것이다.

사용 사례

주로 resize 이벤트 처리 혹은 ajax 요청을 위한 입력 필드 자동완성 UI 구현, 버튼 중복 클릭 방지 등에 사용한다.

Intersection Observer API

쓰로틀에 대해 익숙하지 않았던 이유 중 하나는 스크롤 이벤트 관리 시, 이미 실무에서는 Intersection Observer API를 사용하고 있었기 때문이다.

소개

Intersection Observer API는 상위 요소 또는 최상위 문서의 viewport와 대상 요소 사이의 변화를 비동기적으로 관찰할 수 있는 수단을 제공합니다.

Intersection Observer API는 특정 요소가 다른 요소와의 교차점에 들어가거나 나갈 때 또는 두 요소 간의 교차점이 지정된 양만큼 변화될 때 실행되는 콜백 함수를 코드에 등록할 수 있습니다.

Intersection Observer는 설명에서도, 또한 사용 사례에서도 알 수 있듯 기존 scroll 이벤트의 문제점을 개선하고자 개발되었다.

Intersection?

왜 Intersection(혹은 교차 관찰자)라는 표현에 대한 의문이 생겼는데, 이는 해당 WebAPI가 루트요소와 타겟요소의 교차 지점을 관찰하기 때문이다.

사용 방법

교차 관찰자 생성

let options = {
  root: document.querySelector("#scrollArea"),
  rootMargin: "0px",
  threshold: 1.0,
};

let observer = new IntersectionObserver(callback, options);

여기서 전달되는 option의 경우 다음과 같은 요소들을 포함할 수 있다.

option 종류

  • root 대상 가시성을 체크하기 위한 뷰포트로 사용되는 요소(default: 브라우저 뷰포트)
  • rootMargin 루트 주위의 여백 설정
  • thereshold 관찰자의 콜백이 무조건 실행되어야 하는 대상의 가시성 백분율을 나타내는 숫자 또는 숫자 배열. 예를 들어서 50% 넘어간 지점에서 콜백을 실행시키고 싶다면 0.5라고 지정하면 된다.

요소 설정

target 요소를 전달한다.

let target = document.querySelector("#listItem");
observer.observe(target);

// observer를 위해 설정한 콜백은 바로 지금 최초로 실행됩니다
// 대상을 관찰자에 할당할 때까지 기다립니다. (타겟이 현재 보이지 않더라도)

어째서 더 적절할까?

이 의문과 관련해서 성능을 직접 비교한 좋은 글이 있었다.
Scroll listener vs Intersection Observers: a performance comparison

Percentage of total time doing scripting work

Scroll Listener — No Caching & No Throttling: 48.9%

Scroll Listener — Caching & No Throttling: 43.5%

Scroll Listener — Caching & Throttling: 28.9%

Intersection Observer: 23.3%

caching 과정을 겹쳐도 intersection observer의 성능이 더 우수함을 알 수 있고, 이 성능은 메인 스레드의 성능을 의미한다. 결국 Intersection Observer를 이용한다는 것은 WebAPI에 이벤트를 위임하는 것이고, 따라서 자연스럽게 메인 스레드의 자유도도 보장한다고 볼 수 있을 것이다.

in React

React에서는 custom hook을 이용해서 공통화 하는 것이 적절했다!
아래는 usehooks의 useIntersectionObserver 예시와 package이나, 간단하게 이용하기에 정의가 그리 어렵진 않으므로 직접 작성하여 사용하여도 무방할 것 같다.

usehooks의 useIntersectionObserver
react-intersection-observer(npm)

추가적으로…

requestAnimationFrame을 이용해 쓰로틀링 적용 시, repaint를 개선한 사례에 대한 글이다.
scroll event 최적화로 웹페이지 성능 개선하기

참고문헌

모던 자바스크립트 deep dive(2023)
[Javascript] 디바운싱(debouncing)과 쓰로틀링(throttling)
실무에서 느낀 점을 곁들인 Intersection Observer API 정리

profile
프론트엔드 일짱되기

0개의 댓글

관련 채용 정보