[Javascript] 쓰로틀링 & 디바운싱 (throttle & debounce)

SOLEE_DEV·2021년 1월 16일
4

Javascript

목록 보기
2/19
post-thumbnail

필요했던 이유?

프로젝트를 진행하며 이벤트 리스너를 등록하다 보니, scroll, input에 값이 변경될 때 이를 검사하는 onChange() 메소드가 너무 짜잘한 값까지 (굳이 탐색이 필요하지 않은..) 반응하는 문제가 발생하였다...! 개발 진행하다보면 성능에 더욱 문제를 일으킬 것 같다는 찜찜한 생각이 갖다가 찾게 된 성능 향상 방법!

1. 개념 & 나오게 된 이유

일단 throttle, debounce 이 두가지 방법은 모두 DOM 이벤트를 기반으로 실행하는 JS를 성능상의 이유로 JS의 양적인 측면, 즉 이벤트를 제어하는 방법이다.

예를 들어 스크롤 이벤트를 보고 있다고 하면, 사용자가 스크롤을 움직일 때 마다 수 많은 스크롤 이벤트가 발생한다. 컴포넌트의 'PX'에 따라 이벤트 발생 횟수는 비례적으로 증가!

이렇게 되면 매번 스크롤 이벤트에 대한 콜백이 발생하고 그 콜백이 수행하는 일이 매우 큰 리소르를 잡아먹게 된다. 이는 결국에는 서비스의 성능 저하, 사용자 경험 저하를 야기하게 된다.

이를 해결하기 위한 해결책으로 초기엔 'onScroll 이벤트 외부에서 일정 시간마다 250ms 씩 실행되는 루프'라는 간단한 기술을 활용해 과도한 이벤트를 처리하였는데, 현재 사용 중인 해결책이 바로 ThrottleDebounce 개념!

ThrottleDebounce는 이벤트 핸들러가 많은 연산을 수행하는 경우에 대해 제약을 걸어 제어할 수 있는 수준으로 이벤트를 발생시키는 것을 목표로 하는 기술이다.

2. 쓰로틀링 (Throttling)

Throttling은 이벤트를 일정한 주기마다 발생하도록 하는 기술이다.
예를 들어 Throttle의 설정 시간으로 1ms를 주게 되면 해당 이벤트는 1ms 동안 최대 한번만 발생하게 된다. (너무 짜잘한 값에 대해 일일이 반응할시에 발생하는 성능 저하를 막기 위해 사용)
=> 마지막 함수가 호출된 후 일정 시간이 지나기 전에 다시 호출되지 않도록 하는 것

특성 자체가 실행 횟수에 제한을 거는 것이기 때문에 일반적으로 성능 문제 때문에 많이 사용한다.

ex) 무한 스크롤링 페이지

사용자가 footer에서 얼마나 떨어져 있는지 확인해야하고 사용자가 맨 아래로 스크롤 했다면 Ajax를 통해 더 많은 콘텐츠를 요청해 페이지에 추가해야 한다.

디바운싱은 사용자가 스크롤링을 멈출 때만 이벤트를 발생시키므로 디바운싱보다는 스로틀이 적합할 수 있다. 사용자가 footer에 도달하기 전에 콘텐츠를 가져와야 하기 때문이다.

즉, throttle을 통해 사용자 위치가 얼마나 footer로 부터 떨어져 있는지 항상 확인할 수 있다.

3. 디바운싱 (Debouncing)

Debouncing는 이벤트를 그룹화하여 특정시간이 지난 후 하나의 이벤트만 발생하도록 하는 기술이다. 즉, 순차적인 호출을 하나의 그룹으로 "그룹화"할 수 있다.
(연이어 호출되는 함수들 중, 마지막 함수(또는 제일 처음)만 호출하도록 하는 것)

ex) Ajax 요청이 있는 자동 완성 양식의 키 누르기 예제

검색 쿼리를 입력하는 input 태그에 이벤트를 등록하면, 입력하는 글자 수 만큼의 수 많은 이벤트가 발생한다. 이와 같은 낭비는 유료 API를 사용했을 때 큰 문제로 작용한다. 그렇기 때문에 디바운싱은 비용적인 문제와도 큰 관련이 있다. 그렇기 때문에 최종적으로 작성한 마지막 쿼리에 대해서만 Ajax 요청을 보내도록 설계하면 이를 막을 수 있다.

4. Debounce와 Throttle의 차이점

디바운싱과 스로틀의 가장 큰 차이는 Throttle적어도 X 밀리 초마다 정기적으로 기능 실행을 보장한다는 것이다. Debouce는 아무리 많은 이벤트가 발생해도 모두 무시하고 특정 시간 사이에 어떤 이벤트도 발생하지 않았을 때 딱 한번만 마지막 이벤트를 발생시키는 기법이다.
따라서 5ms가 지나기 전에 계속 이벤트가 발생할 경우, 콜백에 반응하는 이벤트는 발생하지 않고 계속 무시된다.

5-1. Lodash 모듈을 활용한 적용 방법 (Vue.js)

import * as _ from 'lodash'

const handleInput = _.debounce(async(event: any) => { 
  ...
}, 33);
  
const handleScroll = _.throttle(async(event: any) => { 
  ...
}, 33);

이렇게 _.debounce, _.throttle로 이벤트 함수를 감싸고, 원하는 이벤트 주기(ms)를 작성해주면 된다!

5-2. watch에 debounce 적용하기 (Vue.js)

import * as _ from 'lodash'

watch(searchInput, _.debounce((searchInput, prevSearchInput) => {
  ...
}, 33);

watch로 감지할 데이터 프로퍼티로 값을 지정하는 함수를 debounce로 감싸기만 하면 됨

포스팅 내용 출처

profile
Front-End Developer

0개의 댓글