이 영역을 누르면 첫 페이지로 이동
lucid_dream 블로그의 첫 페이지로 이동

lucid_dream

페이지 맨 위로 올라가기

lucid_dream

다양한 상상을 현실로 만드는 멀티 크리에이터를 꿈꾸고 있습니다 ❤️

연속으로 발생하는 이벤트를 제어하는 방법

  • 2021.10.07 02:42
  • 🌈 기술스택/JavaScript
글 작성자: NoHack
728x90

Event Controls

HTML의 DOM 요소를 조작하면서 발생하는 이벤트 중 input, mousemove, resize, scroll 등의 이벤트는 짧은 시간 간격으로 연속해서 발생합니다. 이러한 이벤트들에 함수를 등록해서 사용하는 경우, 너무나 잦은 호출로 인해 성능 저하를 불러올 수 있습니다. 그렇기 때문에 연속적으로 발생하는 이벤트들을 그룹화하여, 원하는 순간에만 호출될 수 있도록 하는 기법을 소개하려 합니다.

본문에서는 간단한 예제만 소개하기에, 프로젝트에서는 Lodash와 같은 라이브러리 사용을 추천합니다.

디바운스

디바운스(Debounce)는 연속으로 발생하는 이벤트의 마지막 이벤트만 호출할 수 있도록 하는 기법입니다. 만약 우리가 외부의 API를 호출해서 사용한다 하면 보통 요청 제한 횟수(Limit)가 걸려있을텐데, 이를 짧은 시간 안에 연속으로 호출하게 된다면 할당량을 금방 소모하게 되어 큰일입니다. 그렇기 때문에 호출이 필요한 부분에 디바운스를 적용한다면, 이와 같은 문제를 사전에 방지할 수 있습니다. 이 외에도 디바운스는 input의 값이 변경될 때, 창의 크기가 변경되어 resize가 발생할 때 적용해볼 수 있습니다.

다음은 input 이벤트에 디바운스를 적용한 예시입니다.

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <title>Debounce</title>
    <style>
      body {
        padding-top: 2rem;
        text-align: center;
      }

      input {
        width: 600px;
        padding: 0.625rem;
        font-size: 1.2rem;
      }
    </style>
  </head>
  <body>
    <input type="text" />
    <script>
      const text = document.querySelector('input');

      const debounce = (callback, delay) => {
        let timer;
        return (event) => {
          // 실행 중인 타이머가 있다면, 제거 후 재생성
          if (timer) clearTimeout(timer);
          timer = setTimeout(callback, delay, event);
        };
      };
      
      text.addEventListener(
        'input',
        debounce((e) => {
          console.log(e.target.value);
        }, 1000)
      );
    </script>
  </body>
</html>

콘솔에서 결과를 확인해 보면, 사용자가 입력을 마친 시점에만 함수가 호출되는 것을 확인할 수 있습니다.

스로틀

디바운스가 바인딩된 함수를 마지막에만 호출하는 것이라면, 스로틀(Throttle)은 일정한 간격에 맞춰 함수를 호출하는 기법입니다. 스로틀은 보통 scroll과 관련된 이벤트에 적용하거나, 무한 스크롤을 구현할 때 발생하는 성능 저하를 막기 위해 사용합니다.

아래는 스크롤 이벤트에 바인딩된 함수가 얼마나 호출되는지 비교해보는 코드입니다.

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <title>Throttle</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }

      .container {
        width: 300px;
        height: 300px;
        margin: 0 auto;
        overflow-y: scroll;
      }

      .box {
        width: 100%;
        height: 2000px;
        background-color: grey;
        overflow: hidden;
      }

      .text {
        padding-top: 2rem;
        text-align: center;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="box"></div>
    </div>
    <p class="text">
      스로틀 적용 X: <span>0</span>회 호출<br />
      스로틀 적용 O: <span>0</span>회 호출
    </p>
    <script>
      const container = document.querySelector('.container');
      const text = document.querySelector('.text');

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

        return (event) => {
          // 타이머가 호출되면, 함수를 실행하고 타이머 제거
          if (timer) return;
          timer = setTimeout(() => {
            callback(event);
            timer = null;
          }, delay);
        };
      };

      container.addEventListener('scroll', (e) => {
        text.children[0].innerText = +text.children[0].innerText + 1;
      });

      container.addEventListener(
        'scroll',
        throttle((e) => {
          text.children[2].innerText = +text.children[2].innerText + 1;
        }, 300)
      );
    </script>
  </body>
</html>

디바운스는 새로운 요청이 들어올 때 타이머를 새롭게 초기화해주는 반면, 스로틀은 타이머가 이미 존재하면 아무런 동작을 하지 않습니다. 타이머가 실행되어서야 내부에서 타이머를 제거하기 때문에, 일정한 간격으로 이벤트 함수를 호출할 수 있게 됩니다.

저작자표시 비영리 동일조건 (새창열림)

'🌈 기술스택 > JavaScript' 카테고리의 다른 글

비동기 처리를 위한 문법 (Promise)  (0) 2021.10.08
자바스크립트에 동시성을 부여하는 이벤트 루프  (0) 2021.10.07
코드 실행에 필요한 정보를 담은 실행 컨텍스트  (0) 2021.10.05
자기 자신을 가리키는 값 this  (0) 2021.10.03
자바스크립트 코드의 유효 범위 Scope  (0) 2021.10.03

댓글

이 글 공유하기

  • 구독하기

    구독하기

  • 카카오톡

    카카오톡

  • 라인

    라인

  • 트위터

    트위터

  • Facebook

    Facebook

  • 카카오스토리

    카카오스토리

  • 밴드

    밴드

  • 네이버 블로그

    네이버 블로그

  • Pocket

    Pocket

  • Evernote

    Evernote

다른 글

  • 비동기 처리를 위한 문법 (Promise)

    비동기 처리를 위한 문법 (Promise)

    2021.10.08
  • 자바스크립트에 동시성을 부여하는 이벤트 루프

    자바스크립트에 동시성을 부여하는 이벤트 루프

    2021.10.07
  • 코드 실행에 필요한 정보를 담은 실행 컨텍스트

    코드 실행에 필요한 정보를 담은 실행 컨텍스트

    2021.10.05
  • 자기 자신을 가리키는 값 this

    자기 자신을 가리키는 값 this

    2021.10.03
다른 글 더 둘러보기

정보

lucid_dream 블로그의 첫 페이지로 이동

lucid_dream

  • lucid_dream의 첫 페이지로 이동

검색

메뉴

  • All categories
  • About me
  • Guest Book

카테고리

  • 분류 전체보기 (122)
    • 💦 일상뻘글 (1)
    • ⭐️ 프로젝트 (7)
      • 사이드 프로젝트 (1)
      • 스터디 노트 (6)
    • 🌈 기술스택 (31)
      • Web Basic (10)
      • JavaScript (14)
      • React (0)
      • Git (7)
    • 💻 컴퓨터공학 (28)
      • 자료구조 (13)
      • 알고리즘 (7)
      • 운영체제 (4)
      • 소프트웨어 공학 (4)
    • 📝 문제풀이 (55)
      • 프로그래머스 (55)
      • 과제관 (0)
    • 🐹 취미생활 (0)
      • Film Log (0)
      • Cover Song (0)

댓글

정보

NoHack의 lucid_dream

lucid_dream

NoHack

나의 외부 링크

  • Github
  • Instagram

블로그 구독하기

  • 구독하기
  • RSS 피드

방문자

  • 전체 방문자
  • 오늘
  • 어제

티스토리

  • 티스토리 홈
  • 이 블로그 관리하기
  • 글쓰기
Powered by Tistory / Kakao. Copyright © NoHack.

티스토리툴바