삼성청년소프트웨어아카데미를 수료하며, 진행했던 프로젝트 중, 가장 애착이 있고 많은 노력을 쏟은 "나들서울" 프로젝트의 리펙토링을 진행하기로 하였다. 기존 끝내지 못했던 버그들을 완료 한 후 (렌더링 버그, Reducer 버그 등...) 프로젝트를 더욱 enrich 할 요소들을 탐색하던 중, 큐레이션의 꽃이자 프로젝트의 메인 요소 중 하나인 "좋아요" 및 "찜하기" 버튼과 관련된 부분을 건들여보고자 하였다.
SNS 큐레이팅 웹 서비스 답게, 사용자는 큐레이터들의 코스를 찜할 수 있고, 지도에서 찾아 본 장소를 "좋아요"로 저장하여, 추 후 활용 할 수 있다.
현재 배포된 버전을 기준으로, 좋아요 버튼은 수시 때때로 먹통이 된다. (현재 develop 버전에서는 일정한 term을 두고 누를 시 원활하게 작동)
파악한 이유로는 크게 두가지가 있다.
1. 사용자가 좋아요 버튼을 수시로 누를 경우, Response가 오기전에 Request가 쌓여 오작동을 한다. (View 부분은 Store의 Reducer를 통하지 않은 컴포넌트의 state로 이루어진다)
2. 현재 Backend의 Api는 두개의 Get Method를 통해 좋아요와 좋아요 취소를 한다. 이때 "좋아요"가 디비에 저장된 상태에서 "좋아요"를 저장하는 Get Method를 호출 시, 버그가 발생한다. (반대로도 똑같다)
2번 부분에 대해, Backend 설계 시, 디비는 모든 상권 정보를 담고 있지 않다 (우리는 제한적인 용량과 카카오 Maps의 Api를 활용하므로). 따라서 좋아요와 좋아요를 취소하는 부분은 하나의 Api 혹은 현 DB에 있는 상태를 확인 한 후, 동작을 이루지 못 할 수 도 있다. (로직이 많아져 시간이 증가하거나, 혹은 발생할 수 있는 에러가 숨겨지는 현상이 일어 날 수도 있을 것 같다).
또한 1번의 근본적인 비동기 통신의 문제도 있기에, debounce & throttle 을 고려하여 버튼에 도입하고자 하였다.
그렇다면 debounce & throttle은 무엇일까?
자바스크립트의 꽃은 당연 이벤트 리스너와 핸들러를 꼽을 수 있을 것이다. 기존 정적이었던 페이지들이 동적으로 변하면서, 사용자와 수 많은 인터렉션을 제공한다. 다양한 인터렉션 중, 수많은 이벤트들이 발생하는 경우가 있다. 사실 위와 같이, 사용자의 클릭은 애교? 인 수준의 이벤트들도 흔하게 볼 수 있다. 가장 흔한 예 중 하나는 마우스 스크롤 이벤트 일 것이다.
이렇게 수많은 이벤트가 발생 할 때, 하나의 이벤트마다 로직이 들어가고, api를 호출한다 생각하면, 정말로 끔찍하다...
그렇기에 이벤트를 제한 할 수 있는 방법으로 debounce 와 throttle이 있다.
사용자의 입력 동안, 입력 주기가 발생한다. 사용자가 1을 입력한 후, 200ms 후에 2를 입력했다 하면, 200ms의 입력 주기가 발생했다 하자.
Debounce
디바운스는 제한한 입력 주기가 끝나면, 출력한다.
Throttle
쓰로틀은 일정 시간의 입력을 모아 한번씩 출력을 제한다.
Debounce는 말과 같이 제한한 입력 주기가 끝나기를 기다린다. 예를들어, 사용자로부터 검색어를 입력 받고, 그 검색어의 관련어들을 출력해주는 로직을 만든다 생각하자.
이때 검색이란 단어를 한글로 타이핑하는 동안, ㄱ+ㅓ+ㅁ+ㅅ+ㅐ+ㄱ, 총 6번의 입력이 발생한다. 만약 debounce나 throttle을 주지 않는다면, 6번동안 서버와 통신하여, 해당 관련 검색어 데이터를 받아올 것이고, 이를 출력해주려 할 것이다.
이때 debounce로 처리를 하려하고, 입력 주기를 200ms라 가정, 사용자의 입력이 모두 200ms안에 이루어 질 경우, 가장 마지막으로 입력한 'ㄱ'으로 부터 200ms 이후 입력 주기가 끝났음을 감지, 서버와 통신하여 관련 검색어 데이터를 받아 올 것이다.
throttle로 처리를 하고자 하고, 입력 주기를 200ms로 가정했을 때, 사용자의 200ms 동안 이루어진 가장 최근의 검색어를 서버에 request 할 것이다. 만약 사용자가 100ms의 속도로 타이핑을 한다 하면, 'ㄱ+ㅓ', 'ㄱ+ㅓ+ㅁ+ㅅ', 'ㄱ+ㅓ+ㅁ+ㅅ+ㅐ+ㄱ' 총 3번의 request를 해당 시간 마지막 입력을 바탕으로 요청하게 될 것이다.
결국 이 둘 중 고려해야 할 부분은 이벤트의 발생 시점 이다. 주기적으로 이벤트를 발생 시키되, 그 횟수를 제한하고 싶다면 throttle이 더욱 어울릴 것이고, 가장 마지막으로 이루어진 이벤트를 바탕으로 입력 주기가 끝났을 때 한번 발생하고 싶다면 debounce가 더욱 어울릴 것 이다.
Debounce 예시 : 드래그 이벤트, 리사이징 이벤트 등 마지막 입력 값이 최종 값이 될 경우
Throttle 예시: 무한 스크롤 (스크롤 중, 다시 올라 갈 수도 - 내려 갈 수도 있다. 해당 영역(Footer로 부터 떨어진 일정 영역)을 지나 쳤을 때가 아닌, 마우스 스크롤 이벤트 중, 일정 시간 내의 마지막 위치에 따라 컨텐츠를 로딩 시킬 수 있다)
현재 프로젝트의 경우, 좋아요 버튼이 수시로 눌릴 수 있다. 하지만 결국 가장 중요한 것은, 사용자의 마지막 입력 값이다. 좋아요를 몇번 누르던, 사용자가 마지막으로 누른 값이 결국 최종 상태가 될 것이다.
lodash 의 debounce & throttling
lodash는 JavaScript의 인기있는 라이브러리 중 하나이다.
array, object, string 등 데이터의 필수적인 구조를 쉽게 다룰 수 있게끔 도와준다.
순수 자바스크립트로 이루어진 이 라이브러리는 브라우저에서 지원하지 않는 성능이 보장되어있는 다양한 메소드를 포함하며, 퍼포먼스 측면에서 native보다 더 낫고, 패키지 매니저를 통해 쉽게 사용할 수 있다.
설치: npm i --save lodash
const debouncedClickDisLike = debounce(() => {
// 마커 정보를 바탕으로 정보의 매장을 좋아요 취소하는 리듀서
dispatch(clickStoreLikeCancel(clickedMarkerInfo.storeInfoDto));
}, 500);
const userClickHeart = () => {
//likeStoreClicked는 Redux Store에 저장되어있는 매장 좋아요 클릭 여부 state
if (likeStoreClicked) {
debouncedClickDisLike();
} else {
debouncedClickLike();
}
};
'개발일지' 카테고리의 다른 글
[크롬 익스텐션: 06] StompJs & SockJs, 디자인 및 구현 - 2 (0) | 2022.06.23 |
---|---|
[크롬 익스텐션: 05] StompJs & SockJs, 디자인 및 구현 - 1 (0) | 2022.06.23 |
[크롬 익스텐션: 04] 클라이언트 - 소셜 로그인 (0) | 2022.06.09 |
[크롬 익스텐션: 03] sockjs-client를 이용한 소켓 통신 (1) | 2022.06.05 |
[크롬 익스텐션: 02] Manifest V3 (0) | 2022.06.03 |