Throttle

Dorr·2021년 9월 10일
0
post-custom-banner

스크롤 이벤트

window의 scroll 이벤트는 스크롤 바를 움직일 때마다 발생한다. 따라서 많은 기능을 하거나 무거운 이벤트핸들러를 바인딩 했을 때 과부하가 올 수 있고 좋지 못한 성능을 보일 수 있다.

위의 화면을 보면 스크롤을 조금만 움직여도 스크롤 이벤트의 발생 횟수가 급격하게 증가하는 것을 알 수 있다. 그렇다면 이런 문제를 해결할 수 있는 방안은 무엇일까??


Throttle이란?

throttle은 한 함수가 연속적으로 발생시 일정한 시간을 주기로 두고 그 주기 내에 발생한 함수는 여러번 호출되더라도 한번만 실행하게 해주는 기술이다. 쉽게 말해 출력을 조절하는 기술이라 생각하면 된다. debounce외 같이 시간의 흐름에 따라 함수의 실행 횟수를 제어하는 방법 중 하나다.

앞서 얘기했듯이 주로 스크롤 이벤트에서 throttle을 적용한다. 스크롤 바를 움직일 때마다 호출되는 매우 많은 함수들이 모두 실행된다면 좋지않은 사용자 경험을 제공할 수 있기에 throttle로 함수의 실행을 조절해준다.

throttle 적용하기

우선 기본적인 스크롤 이벤트를 적용한 코드는 다음과 같다.

let countScroll = 0; 

window.addEventListener('scroll', handleScroll)

function handleScroll(e) {
  countScroll++;
  console.log(countScroll);
}

이 경우 위에서 본 것처럼 스크롤이 약간만 움직여도 굉장히 많은 함수를 호출한다.
여기에 throttle을 적용해서 문제를 해결해보자.

우선 throttle은 최초로 발생한 함수를 일정시간동안 실행을 유보시킨다.
따라서 setTimeout 함수을 이용해 코드로 작성하면 다음과 같다.

let countScroll = 0; 

window.addEventListener('scroll',(e) => {
    setTimeout(handleScroll, 500)
})

function handleScroll(e) {
  countScroll++;
  console.log(countScroll);
}

이 코드는 함수의 실행시점을 호출시점보다 500ms 뒤로 눚춰준다.
이제 이 500ms라는 짧은 시간안에 호출되는 함수들의 실행을 취소하는 코드를 작성해보자.

let countScroll = 0; 
let timerId = null; // timerId를 null로 초기화

window.addEventListener('scroll', (e) => {
  // timerId가 null일 경우에만 실행
  if (timerId === null) {
    // timerId에 setTimeout의 식별자를 할당
    timerId = setTimeout(() => {
      // 주어진 시간 지나먄 timerId에 null을 할당
      timerId = null;
      handleScroll()
    }, 200)
  }
})

function handleScroll() {
  countScroll++;
  console.log(countScroll);
}

이렇게 작성한다면 timerId가 null인 상황, 즉 함수의 최초 호출시점과 주기가 끝난 후 처음으로 호출되는 함수의 경우만 실행되고 그외의 함수들의 실행은 무시하게 된다.

이번에는 throttle의 사용성을 높이기위해서 함수로 추상화해보자.

function throttle(cb, period) {
  let timerId = null;
  
  //함수를 return 한다.
  return (...args) => {
    if(timerId === null) {
    	timerId = setTimeout(() => {
        	timerId = null;
          	cb(...args)
        }, period)
    }	
  }
}

throttle이 적용된 스크롤 이벤트

이렇게 throttle을 적용했을 경우 함수의 실행횟수가 조절되는 것을 확인 할수 있다.

post-custom-banner

0개의 댓글