Post

throtting,debouncing

#throtting과 debouncing

과한 이벤트를 막아 서버에 부담을 줄이기 위해 사용하는 테크닉

■ debouncing (디바운싱)

https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJF91e%2FbtrCW1H0yB0%2F4zUwtPLlGE2wofdMY3TCV0%2Fimg.png

빈번하게 발생하는 이벤트를 ‘특정 시간 이후에 한번만’ 실행 시키는 최적화 기법

먼저 발생한 이벤트가 처리를 대기하며, 대기하는 도중 새 이벤트가 발생하면 이전 이벤트의 대기를 취소하고 해당 이벤트를 기준으로 다시 처리를 대기한다. 특정 시간동안 처리는 대기하게 되며, 연속적으로 발생한 이벤트는 마지막으로 발생한 기준으로 처리된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
// ES6
function debounced(delay, fn) {
  let timerId;
  return function (...args) {
    if (timerId) {
      clearTimeout(timerId);
    }
    timerId = setTimeout(() => {
      fn(...args);
      timerId = null;
    }, delay);
  };
}
1
2
3
const myHandler = (event) => // do something with the event
const dHandler = debounced(200, myHandler);
domNode.addEventListener("input", dHandler);

예시 - 검색 결과 요청하기

검색어를 치자마자 엔터 없이도 결과가 바로바로 보여주려면 항상 input 이벤트에 대기하고 있어야 한다.

1
<input id="search-query" />
1
2
3
document.querySelector("#search-query").addEventListener("input", function (e) {
  // 검색결과받아오는 함수
});

위의 경우 ‘디즈니’를 검색하기 위해 input 창에 디즈니를 입력하게 된다면, ㄷ, 디, 딪, 디즈, 디즌, 디즈니를 작성할 때마다 이벤트가 실행됩니다. 긴 쿼리를 입력했을 경우 불필요한 요청이 발생하며, 과한 이벤트로 인해 소프트웨어에 부담을 줄 수 있습니다.

이런 불필요한 요청, 과한 이벤트를 막기 위해서는 어떻게 해야할까요?

보통 사람들은 타자를 연달아치며 한번에 검색어를 입력하기 때문에, 입력이 끝난 후 요청을 보내면 과한 이벤트를 막을 수 있습니다. 타자를 칠 때마다 타이머를 설정해, 특정 시간동안 입력이 없으면 입력이 끝난 것으로 판단하고 이벤트를 실행시키면 됩니다. 특정 시간 이전에 다시 타자 입력이 발생하면 이전 타이머는 취소하고 새로운 타이머를 설정합니다.

따라 2초 동안 입력이 없다면 이벤트를 실행하도록 하는 코드를 작성해 성능을 최적화할 수 있습니다.

1
2
3
4
5
6
7
8
9
var timer;
document.querySelector("#search-query").addEventListener("input", function (e) {
  if (timer) {
    clearTimeout(timer);
  }
  timer = setTimeout(function () {
    // 검색결과받아오는 함수
  }, 200);
});

■ throttle (쓰로틀링)

https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKf2ea%2FbtrC4gxA6oV%2FuGJPEWHqyUWjkeZdNqbsi0%2Fimg.png

빈번하게 발생하는 이벤트를 ‘일정한 간격으로 한번만’ 실행 시키는 최적화 기법

보통 성능 문제 때문에 많이 사용되며, 짧은 주기로 실행되는 이벤트를 조절하고 싶은 곳에 사용합니다.

1
2
3
4
5
6
7
8
9
10
11
12
// ES6 code
function throttled(delay, fn) {
  let lastCall = 0;
  return function (...args) {
    const now = new Date().getTime();
    if (now - lastCall < delay) {
      return;
    }
    lastCall = now;
    return fn(...args);
  };
}
1
2
3
const myHandler = (event) => // do something with the event
const tHandler = throttled(200, myHandler);
domNode.addEventListener("mousemove", tHandler);

예시 - 스크롤할 때 트리거 막기

스크롤 이벤트를 등록하면 스크롤을 할 때마다 이벤트가 실행된다.

1
2
3
4
5
6
7
8
9
10
useEffect(() => {
  window.addEventListener("scroll", handleScroll);
  return () => {
    window.removeEventListener("scroll", handleScroll); //clean up
  };
}, []);

const handleScroll = () => {
  console.log("scrolled");
};

위의 경우 스크롤을 조금만 해도 콘솔창에 “scrolled”가 100개 이상씩 찍히는 것을 확인할 수 있다. 만약 스크롤하였을 때 실행되는 것이 console.log(“scrolled”);보다 더 무거운 함수라면 어떻게 될까? 과한 이벤트로 인해 제대로 작동하지 않을 것이다.

이러한 과한 트리거를 막으려면 어떻게 해야할까?

일정한 시간을 간격으로 이벤트를 실행시키면 됩니다. 하단 파란 박스를 스크롤해보세요. throttle을 사용하여 이벤트 횟수를 제한했을 때와 그렇지 않았을 때의 이벤트 발생 횟수를 확인할 수 있습니다.

See the Pen scroll-throttling by 혬 (@jexbagvl-the-reactor) on CodePen.


참고사이트

This post is licensed under CC BY 4.0 by the author.