일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- javascript
- 트리의지름
- 이모티콘할인행사
- 큐
- [1차]캐시
- 도넛과막대그래프
- 벽부수고이동하기
- 자물쇠와열쇠
- 17404
- 파이썬
- 그래프탐색
- 프림알고리즘
- 두큐합같게만들기
- DP
- 징검다리건너기
- 최단경로
- 위상정렬
- 프로그래머스
- 다익스트라
- DFS
- 최소스패닝트리
- 섬연결하기
- 구현
- RGB거리2
- 사이클게임
- 알고리즘
- 거리두기확인하기
- 백준
- BFS
- 파괴되지않은건물
- Today
- Total
블로그 이름 뭐로 하지
[JavaScript] 디바운싱(Debouncing) 본문
최근 벨로그 인기글에서 검색 api 사용을 할 때 계속해서 api를 호출하는 것에 대해 js의 디바운스 개념을 활용해서 최적화하는게 좋다는 글을 본 적 있었다. 그 때도 '나중에 ^^' 다시 공부해야겠다하고 넘겼는데, 지금 하고 있는 프로젝트도 그렇고 예전에 했던 프로젝트나 앞으로 할 개발에 있어서도 알아두고 있어야할 개념이라고 생각해서 공부한 내용을 정리하고자 한다.
디바운스. 어떨 때 써야할까?
스크롤이나 마우스 클릭, api호출 관련한 함수가 불필요하게 너무 많이 실행되는 경우가 있다. 예를 한 번 살펴보자.
사진은 현재 내가 개발 중인 프로젝트이다. 검색어에 따라 지하철 목록을 호출해서 보여줘야 하는데, 현재는 검색어가 ㅅ,서,성,성ㅅ,성수 로 바뀌는 일련의 과정동안 계속해서 api가 호출되고 있다.
당연한 말이지만 몇 초도 안 되는 시간동안 몇십, 몇백개의 함수를 호출하는 것은 작업을 무겁게 만들고, 웹과 서버 모두에게 부담을 줄 수 있다.
이를 해결하기 위해 디바운싱을 활용한다. 이 개념은 Javascript 개념이라기 보다는 프로그래밍 기법 중에 하나이다. 따라서 자바스크립트에서 직접적으로 디바운스라는 이름으로 제공하는 함수같은건 없고, web api인 clearTimeout 와 setTimeout 를 사용해서 디바운스의 기능을 하는 함수를 작성해야 한다. 즉 일종의 최적화 기법이라고 보면 된다.
디바운싱 (Debouncing)
💡 연속해서 호출되는 함수들 중 마지막 함수만 호출하도록 하는 것
searchText가 변경될때마다 지하철목록을 불러오는 api를 호출하는 useGetStations이 실행되기 때문에 사용자가 실수로 길게 검색어를 작성할 때도, 그렇지 않을 때에도 글자를 입력할 때마다 API 호출이 진행되고 있다.
const data = useGetStations(searchText);
onChange={(e) => setSearchText(e.target.value)}
디바운스 적용 후 실행 과정
디바운스를 지정하면 다음과 같이 실행 된다.
- 지정된 딜레이 안에 호출이 여러번 발생 돼도 마지막 1번만 실행한다.
- ex) 딜레이를 1초로 잡는다면 0.9초 뒤에 버튼을 클릭하고, 0.9초 뒤에 또 버튼을 클릭하고, 또 0.9초 뒤에 버튼을 클릭해도 마지막 클릭만 함수를 호출한다.
- 기본적으로 함수 호출이 지연되는 것이다. (setTimeout함수의 특징을 생각하자!)
- ex) 디바운스 딜레이가 1초라면, 1번만 클릭해도 1초 후에 실행된다. (마지막 클릭 이후 1초 뒤에 함수가 실행 된다.)
디바운스 적용 코드
const debounce = <T extends (...args: any[]) => any>(fn: T, delay: number) => {
let timeout: ReturnType<typeof setTimeout>;
return (...args: Parameters<T>): ReturnType<T> => {
let result: any;
if (timeout) clearTimeout(timeout);
timeout = setTimeout(() => {
result = fn(...args);
}, delay);
return result;
};
};
const onChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
setSearchText(e.target.value);
};
const debouncedOnChange = debounce<typeof onChange>(onChange, 500);
.
.
.
return (
<SearchBar
ref={inputRef}
placeholder={cntPage == 'search' ? '지하철 역 이름을 입력해주세요.' : '지하철역'}
onClick={cntPage == 'home' ? () => router.push('/search') : undefined}
onChange={debouncedOnChange}
></SearchBar>
.
.
.
);
위에서 debounce라는 이름의 함수를 훅으로 만들어두면 프로젝트 내에서 디바운스가 필요한 부분이 있을때마다 import해와서 사용할 수 있을 것이다. 이 이에도 이미 디바운스를 구현해둔 라이브러리들이 있어서 불러와서 써줄 수도 있다.
마무리
이번 썸네일 프로젝트에서 검색어를 구현하는 부분과 무한스크롤 부분을 모두 내가 맡았는데 마침 그 두 부분에서 적용할 수 있는 개념이라고 생각해서 지금이라도 공부하게 되어 참 좋았다! 무한스크롤에는 디바운스보다 쓰로틀링이 적합하다고 하는데 쓰로틀링도 공부하고 적용해본 후 가져와봐야겠다.
또 예전에 했던 티타임 프로젝트에서 setTimeout함수를 사용해서 채팅을 구현했었는데(채팅 로직에는 스크롤도 연관되어 있고... 굉장히 복잡하다) 여기에 디바운스를 적용할 수 있다면 더욱 성능을 최적화를 시킬 수 있을까?하는 생각이 들었다. 티타임 코드도 살펴보고 고칠 수 있는 부분이 있다면 고쳐보고 싶다!
'프론트엔드' 카테고리의 다른 글
[React] React 배열 state에 원소 추가할 땐 concat or push? (1) | 2024.02.15 |
---|