ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Group Study, 모던 자바스크립트 Deep Dive] - 41 타이머
    Front-end/Javascript 2023. 3. 26. 18:44
    반응형

    Group study background

    나만 그런건지는 모르겠지만, 실무를 하다보면 잊어버리는 개념들이 있다.

    가끔 FE 뉴비인분들에게 질문을 받는데, 아리송 할때만큼 쪽팔릴때가 없었다.

    인간은 망각의 동물이라고 교수님께서 말씀하셨지만 반복 학습의 힘을 믿는다. React 오픈카톡방에서 모집한 스터디원분들과 함께 "모던 자바스크립트 Deep Dive" 1권 톺아보기를 시작한다!

     

    정보 전달용이 아닌 개인 스터디 레코딩용 포스트입니다.


    41.1 호출 스케줄링

     함수를 명시적으로 호출하지 않고 일정 시간이 경과된 이후에 호출되도록 함수 호출을 예약하는데 이를 호출 스케줄링이라 한다.

    타이머는 빌트인 함수가 아닌 호스트 객체이며 생성하기 위한 setTimeout, setInterval, 제거를 위한 clearTimeout, clearInterval을 제공한다.

     JS 엔진은 단 하나의 실행 컨텍스트(싱글 스레드)를 갖기 때문에 두 가지 이상의 태스크를 동시에 실행할 수 없다. 따라서 setTimeout, setInterval은 비동기 처리 방식으로 동작한다.


    41.2 타이머 함수

    41.2.1 setTimeout/clearTimeout

    세번째 매개변수에 전달해야 할 인수가 있는 경우 param을 전달할 수 있다. 또한 setTimeout은 고유 타이머 id을 반환한다. 따라서 변수에 저장하여 clearTimeout의 input으로 사용되고 타이머를 취소한다.

    매개변수 설명
    func 타이머가 만료된 뒤 호출될 콜백 함수
    * 콜백 함수 대신 코드를 문자열로 전달 가능하지만 권장 x
    delay 타이머 만료 시간(밀리초ms 단위). setTimeout 함수는 delay 시간으로 단 한 번 동작하는 타이머를 생성한다. 인수 전달을 생략한 경우 기본값 0이 지정된다.
    param 호출 스케줄링된 콜백 함수에 전달해야 할 인수가 존재하는 경우 세 번째 이후의 인수로 전달 가능.

    41.2.2 setInterval/clearInterval

    interval 함수는 인수로 전달 받은 시간마다 반복 동작하는 타이머이다. setInterval 전달 인수는 setTimeout과 동일하다.


    41.3 Debounce & Throttle

    어쩌면 이 챕터에서 가장 중요한 개념 중 하나로 보인다. Debounce와 Throttle은 면접에서도 단골 질문이며, 현생의 프로젝트에서도 꼭 사용되는 기법 중 하나이다.

    마우스 scroll || mousemove, 브라우저 resize, input 이벤트 등 같은 이벤트들은 짧은 시간 간격으로 연속해서 발생한다. 이러한 연속적인 이벤트들에 바인딩한 이벤트 핸들러(함수)는 과도하게 호출되어 성능 문제를 발생시킬 확률이 아주아주아주 높다. 

     예를 들어 구글 검색 input tag에 찾고 싶은 문장의 검색어(20~30자)를 타이핑 한다고 가정해보자. input 메서드에 이벤트 핸들러가 바인딩 되어 있다면, 모든 단어를 타이핑하고 때로는 백스페이스로 지울때마다 자동 검색을 위한 api를 호출하게 된다. 자 이렇게 되면 FE 성능은 두 번째 치고, BE engineer에게 쿠사리를 먹지 않을 자신이 있을까....?

     이런 불상사를 피하고 아름다운 세상(?)을 만들기 위해 사용되는 기법이 Debounce와 Throttle이다.

    [예제 41-01]

    <body>
     <button>click me</button>
     <pre>일반 클릭 이벤트 카운터 <span class="normal-msg">0</span></pre>
     <pre>디바운스 클릭 이벤트 카운터 <span class="debounce-msg">0</span></pre>
     <pre>스로틀 클릭 이벤트 카운터 <span class="throttle-msg">0</span></pre>
     <script>
      const $button = document.querySelector('button');
      const $normalMsg = document.querySelector('.normal-msg');
      const $debuonceMsg = 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.addEvnetListener('click', () => {
      	$normalMsg.textContent = +$normalMsg.textContent + 1;
      )}
      $button.addEvnetListener('click', decounce() => {
      	$debuonceMsg.textContent = +$debuonceMsg.textContent + 1;
      )}
      $button.addEvnetListener('click', throttle() => {
      	$throttleMsg.textContent = +$throttleMsg.textContent + 1;
      )}
    </body>

     

    41.3.1 디바운스

    디바운스(debounce)는 짧은 시간 간격으로 이벤트가 연속해서 발생하면 이벤트 핸들러를 호출하지 않다가 일정 시간이 경과한 이후에 이벤트 핸들러가 한 번만 호출되도록 한다. 즉, 디바운스는 짧은 시간 간격으로 ㅂ라생하는 이벤트를 그룹화해서 마지막에 한 번만 이벤트 핸들러가 호출되도록 한다. 

     위의 코드에서 보이는 것처럼  decounce가 반환한 함수는 debounce 함수에 두번째 인수로 전달한 시간(delay)보다 짧은 간격으로 이벤트가 발생하면 이전 타이머를 취소하고 새로운 타이머를 재설정한다. 따라서 delay보다 짧은 간격으로 이벤트가 연속해서 발생하면 debounce 함수의 첫 번째 인수로 전달한 콜백 함수는 호출되지 않다가 delay동안 이벤트가 더 이상 발생하지 않으면 한번만 호출된다.

     위의 예시인 구글 검색 창의 input tag 이벤트에 적합하다고 할 수 있다. 

    적합한 적용 예시: input event

    ref https://llu.is/throttle-and-debounce-visualized/

     

    41.3.2 쓰로틀

    쓰로틀(throttle)은 짧은 시간 간격으로 이벤트가 연속해서 발생하더라도 일정 시간 간격으로 이벤트 핸들러가 최대 한 번만 호출되도록 한다. 즉, 스로틀은 짧은 시간 간격으로 연속해서 발생하는 이벤트를 그룹화해서 일정 시간 단위로 이벤트 핸들러가 호출되도록 호출 주기를 만든다.

    적합한 적용 예시: scroll event

    [그림 41-02]

    ref https://llu.is/throttle-and-debounce-visualized/

     

    반응형

    댓글

Designed by Tistory.