ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 41장. 타이머
    책/모던 자바스크립트 딥다이브 2022. 5. 22. 22:45

    41장. 타이머

    41-1. 호출 스케줄링

    • 일정 시간이 경과된 이후에 호출되도록 함수 호출을 예약하려면 타이머 함수를 사용한다.
    • 이를 호출 스케줄링(scheduling a call) 이라 한다.
    • 타이머 함수는 ECMAScript 사양에 정의된 빌트인 함수 아니다.
    • 브라우저 환경과 Node.js 환경에서 모두 전역 객체의 메서드로서 타이머 함수를 제공한다.
    • JS 엔진은 단 하나의 실행 컨텍스트 스택을 갖기 때문에 두 가지 이상의 태스크 동시 실행할 수 없다.
    • 싱글 스레드로 동작한다.
    • 이런 이유로 타이머함수는 비동기 처리방식으로 동작한다.

    41-2. 타이머 함수

    • delay ms 단위
    • delay default: 0
    • 타이머가 만료되었다고 콜백 함수 즉시 호출을 보장하진 않는다.
    • 태스크 큐에 콜백 함수를 등록하는 시간을 지연할 뿐
    • delay 4ms 이하인 경우 최소 지연 시간 4ms 지정됨.
    // setTimeout
    const timerId = setTimeout(name => console.log(`Hi! ${name}.`), 100, 'Lee');
    // return 값 브라우저환경: 숫자, Node.js 환경: 객체
    
    // clearTimeout 함수의 인수로 전달하여 타이머 취소.
    // 타이머가 취소되면 setTimeout 함수의 콜백 실행되지 않음.
    cleartTimeout(timerId);
    
    // setInterval
    const count = 1;
    const timerId = setInterval(() => {
      console.log(count);
      if (count++ === 5) clearInterval(timerId);
    }, 1000);

    41-3. 디바운스와 스로틀

    • scroll, resize, input, mousemove 와 같은 이벤트는 짧은 시간 간격으로 연속해서 발생하는데 여기 바인딩 된 이벤트 핸들러는 과도하게 호출되어 성능에 문제를 일으킬 수 있다.
    • 디바운스와 스로틀은 짧은 시간 간격으로 연속해서 발생하는 이벤트를 그룹화해 과도한 이벤트 핸들러 호출을 방지하는 기법이다.

    디바운스

    • 짧은 시간 간격으로 발생하는 이벤트를 그룹화해서 마지막에 한 번만 이벤트 핸들러가 호출되도록 한다.

    스로틀

    • 짧은 시간 간격으로 이벤트가 연속해서 발생하더라도 일정 시간 간격으로 이벤트 핸들러가 최대 한 번만 호출되도록 한다.
    <!-- example1 -->
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Title</title>
    </head>
    <body>
    <button class="button">click me</button>
    <pre>일반 클릭 이벤트 카운터 <span class="normal-msg">0</span></pre>
    <pre>debounce 클릭 이벤트 카운터 <span class="debounce-msg">0</span></pre>
    <pre>throttle 클릭 이벤트 카운터 <span class="throttle-msg">0</span></pre>
    <script>
      const $button = document.querySelector('.button');
      const $normalMsg = document.querySelector('.normal-msg');
      const $debounceMsg = document.querySelector('.debounce-msg');
      const $throttleMsg = document.querySelector('.throttle-msg');
      const debounce = (callback, delay) => {
        let timerId;
        return event => {
          if (timerId) clearTimeout(timerId);
          timerId = setTimeout(callback, delay, event);
        }
      };
      const throttle = (callback, delay) => {
        let timerId;
        return event => {
          if (timerId) return;
          timerId = setTimeout(() => {
            callback(event);
            timerId = null;
          }, delay, event);
        };
      };
      $button.addEventListener('click', () => {
        $normalMsg.textContent++;
      });
      $button.addEventListener('click', debounce(() => {
        $debounceMsg.textContent++;
      }, 500));
      $button.addEventListener('click', throttle(() => {
        $throttleMsg.textContent++;
      }, 500));
    </script>
    </body>
    </html>
    
    <!-- example2 -->
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <style>
          .container {
              width: 300px;
              height: 300px;
              background-color: rebeccapurple;
              overflow: scroll;
          }
    
          .content {
              width: 300px;
              height: 1000vh;
          }
      </style>
      <meta charset="UTF-8">
      <title>Title</title>
    </head>
    <body>
    <div class="container">
      <div class="content"></div>
    </div>
    <div>
      일반 이벤트 핸들러 scroll 처리 횟수
      <span class="normal-count">0</span>
    </div>
    <div>
      스로틀 이벤트 핸들러 scroll 처리 횟수
      <span class="throttle-count">0</span>
    </div>
    
    <input type="text">
    <div class="msg"></div>
    
    <script>
      const $container = document.querySelector('.container');
      const $normalCount = document.querySelector('.normal-count');
      const $throttleCount = document.querySelector('.throttle-count');
    
      const throttle = (callback, delay) => {
        let timerId;
    
        return event => {
          if (timerId) return;
          timerId = setTimeout(() => {
            callback(event);
            timerId = null;
          }, delay, event);
        };
      };
    
      let normalCount = 0;
      $container.addEventListener('scroll', () => {
        $normalCount.textContent = ++normalCount;
      });
    
      let throttleCount = 0;
      $container.addEventListener('scroll', throttle(() => {
        $throttleCount.textContent = ++throttleCount;
      }, 100));
    
      //
      const $input = document.querySelector('input');
      const $msg = document.querySelector('.msg');
    
      const debounce = (callback, delay) => {
        let timerId;
    
        return event => {
          if (timerId) clearTimeout(timerId);
          timerId = setTimeout(callback, delay, event);
        }
      };
    
      $input.oninput = debounce(e => {
        $msg.textContent = e.target.value;
      }, 300);
    </script>
    </body>
    </html>
    

    ' > 모던 자바스크립트 딥다이브' 카테고리의 다른 글

    43장. Ajax  (0) 2022.05.22
    42장. 비동기 프로그래밍  (0) 2022.05.22
    46장. 제너레이터와 async/await  (0) 2022.05.15
    45장. 프로미스  (3) 2022.05.14
    44장. REST API  (0) 2022.05.14
킹수빈닷컴