debouncing과 throttling

최정은·2021년 2월 15일
2

debouncing

연이어 호출되는 함수들 중 가장 마지막으로 호출된 함수만 실행되도록 하는 것

주로 ajax 검색에 사용된다. 자동완성 같이 특정 문자열을 다 입력했을때만 API 요청을 보내도록 할 수 있다.

디바운싱을 사용하지 않고 검색을 이용하면 어떻게 될까?

한글자씩 입력할 때 마다 몇자가 입력 되었는지 나타난다.
이럴 경우엔 큰 지장은 없지만 이게 API 요청을 보내는 작업이라면?
계속해서 요청을 보내기 때문에 불필요한 요청을 보내게 될 수도 있다.

예제


위에서 보여준 것은 입력할 때 마다 몇 글자를 입력했는지 알려준다.
디바운싱을 이용하여 1초 동안 입력이 없을 경우에 몇 글자를 입력했는지 알려주는 글자가 나오도록 했다.

const debounce = (fn, delay) => {
  let timer;

  return () => {
    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(() => {
      fn();
      setTimeout(() => {
        notice.innerHTML = "";
      }, delay);
    }, delay);
  };
};

inputElement.addEventListener(
  "input",
  debounce(() => {
    notice.innerHTML = `${inputElement.value.length}자 입력 완료`;
  }, 1000)
);

debounce 함수를 클로저를 이용해서 구현했다. 함수를 반환하고 input 이벤트가 실행될 때 마다 반환한 함수가 실행되도록 했다.
입력창에 글을 작성하고 있을때 timer 변수에 값이 존재하면 해당 timer를 clearTimeout을 통하여 지워주고 새로 timer를 생성해준다.

그런 뒤 입력이 끝나게 되면 setTimeout에 있던 콜백함수가 실행이 되면서 원하는 작업을 수행할 수 있게 한다.

이를 이용해서 AJAX 요청을 보낼 수 있다.
단어를 입력하면 해당 단어가 들어가 있는 영화 목록을 반환하는 getMovies 함수를 구현해봤다.

const getMovies = async () => {
  try {
    const movieName = inputElement.value;
    const result = await fetch(
      `https://api.tvmaze.com/search/shows?q=${movieName}`
    );
    const response = await result.json();

    const movieList = response.map((data) => ({
      id: data.show.id,
      name: data.show.name,
      url: data.show.image?.medium
    }));

    return movieList;
  } catch (e) {
    console.error(e.message);
  }
};
const onInput = async () => {
  const movieList = await getMovies();
  notice.innerHTML = "";
  movieList.map(
    (movie) =>
      (notice.innerHTML += `<li key=${movie.id}>
          ${movie.name}
          <img src=${movie.url} />
	</li>`)
  );
};

inputElement.addEventListener("input", debounce(onInput, 2000));

이런식으로 글자를 입력할 때 마다 api 요청을 보내지 않고 일정 시간동안 입력이 없을 경우 api 요청을 보낼 수 있게 된다.

throttling

마지막 함수가 호출 된 후 일정시간이 지나기 전에 다시 함수를 호출하지 않는 것

보통 스크롤 이벤트를 처리할 때 많이 사용된다. 스크롤을 내릴거나 올릴때 엄청 많은 이벤트가 실행된다.

내릴때마다 이벤트가 발생하는것을 볼 수 있다.

스로틀링을 이용하여 이벤트 호출을 최대한 줄여보도록 한다.

예제


스크롤을 내릴때마다 이벤트가 실행되는것이 아니라 지정된 시간이 지나기 전에 다시 함수를 호출하지 않게한다.
이로 인해 불필요한 이벤트 호출을 줄일 수 있게 된다.

const throttle = (fn, delay) => {
  let timer;

  return () => {
    if (!timer) {
      timer = setTimeout(() => {
        timer = null;
        fn();
      }, delay);
    }
  };
};

window.addEventListener(
  "scroll",
  throttle(() => {
    const scrollY = window.scrollY;
    console.log(`scrollY : ${scrollY}`);
  }, 500)
);

debounce와 마찬가지로 클로저를 이용해서 throttle 함수를 구현했다.
timer가 존재하지 않을 경우 setTimeout을 생성하여 timer 변수에 넣어준다. 그런 뒤 일정 시간이 지나고 나면 timer를 초기화하고 전달된 함수를 실행하도록 한다.

0개의 댓글

관련 채용 정보