23.07.07
throttling & debouncing : 짧은 간격으로 연속해서 이벤트가 발생했을 때 과도한 이벤트 핸들러 호출을 방지하는 기법들
throttling : 이벤트가 짧은 시간 연속으로 발생하지만 이들을 일정시간 단위(= delay)로 그룹화하여 함수를 이벤트 그룹의 처음이나 마지막에만 호출되도록 하는 것
ex. 무한스크롤
// 반복적인 이벤트 동안, delay 간격으로 function 호출
const throttle = (delay) => {
if (timerId) {
// timerId가 있으면 바로 함수 종료
return;
}
// 첫번째 콘솔
console.log(`API요청 실행! ${delay}ms 동안 추가요청은 안받습니다`);
timerId = setTimeout(() => {
// 두번째 콘솔
console.log(`${delay}ms 지남 추가요청 받습니다!`);
timerId = null;
}, delay);
};
정상적일 때
timerId는 null, 그러므로 if문을 지나고 아래로 내려가 첫번째 콘솔이 출력됨setTimeout으로 들어가서 delay 시간만큼 지나고 두번째 콘솔이 출력되는 구조이벤트가 짧은 시간 연속으로 발생할 때
timerId는 null, 그러므로 if문을 지나고 아래로 내려가 첫번째 콘솔이 출력됨setTimeout으로 들어가서 delay 시간이 지나기 전에 사용자가 다시 함수를 호출timerId는 setTimeout으로 할당되어있기 때문에(= 2초) if문 조건에 의해 return되어 함수가 바로 종료됨 => 지정된 delay 내 함수가 한 번만 호출되도록 보장clearTimeout 된 것은 아니니 2초 후에 2번째 콘솔이 출력되고 timerId는 다시 null되는 순서debouncing : 짧은 시간 간격으로 연속해서 이벤트가 발생(= bouncing)하면 함수를 호출하지 않다가(= de) 마지막 이벤트로부터 일정 시간(= delay)이 경과한 후에 함수를 한 번만 호출하도록 하는 것
ex. 입력값 실시간 검색, 화면 resize 이벤트
// 반복적인 이벤트 이후, delay가 지나면 function 호출
const debounce = (delay) => {
if (timerId) {
// 할당되어 있는 timerId에 해당하는 타이머 제거
clearTimeout(timerId);
}
timerId = setTimeout(() => {
// 콘솔
console.log(`이제 요청으로부터 ${delay}ms 지났으므로 API 요청 실행!`);
timerId = null;
}, delay);
};
정상적일 때
timerId는 null, 그러므로 if문을 지나고 아래로 내려가 setTimeout으로 들어감이벤트가 짧은 시간 연속으로 발생할 때
timerId는 null, 그러므로 if문을 지나고 아래로 내려가 setTimeout으로 들어감timerId는 setTimeout으로 할당되어있기 때문에 if문으로 올라가 clearTimeout이 실행되어 timerId는 다시 null이 됨
Q. 근데 만약 throttling 함수를 호출하고 페이지 이동을 한다면 ?
A. 이벤트는 유지되고 있음 => 메모리 누수
메모리 누수 : 메모리가 사용되지 않는 시점에서도 메모리를 반환하지 않고 계속 점유하고 있는 현상
let timerId = null;
useEffect(() => {
return () => {
// 언마운트 시
if (timerId) {
clearTimeout(timerId);
}
};
}, []);
메모리 누수를 막기 위해 useEffect를 사용해서 언마운트 될 때(= 홈이라는 컴포넌트가 사라질 때) clearTimeout을 실행해서 timerId를 제거해주는 식으로 메모리 누수를 막을 수 있음
만약 메모리 누수를 막지 않는다면 프로그램이 비정상적으로 작동하거나 크래시가 발생하는 등의 문제가 생길 수가 있으니 신경써서 점검해야 함 !
lodash : _ 라이브러리
라이브러리이기 때문에 yarn add lodash로 설치해야 함 => lodash에는 debounce, throttle 함수를 제공하고 있어서 lodash를 사용하게 된다면 해당 함수를 직접 구현할 필요가 없음
debounce 기본형
// 첫번째 인자 함수, 두번째 인자 시간
_.debounce( func, wait, options )
debounce 커스텀
// 첫번째 인자 함수, 두번째 인자 시간
const debounce = (callback, delay) => {
let timerId = null;
// debounce 함수 내부에 있는 closure라는 특성 때문에 내부 변수 뿐만 아니라 외부 변수(ex. timerId)를 참조할 수 있음
return (...args) => {
if (timerId) {
clearTimeout(timerId);
}
timerId = setTimeout(() => {
callback(...args);
}, [delay]);
};
};
// useCallback 훅을 통해 메모이제이션을 해놔서 렌더링이 다시 일어나더라도 새롭게 함수가 반환되는게 아니라
// debounce 함수 내부에 closure 함수 특성 부분까지를 기억하고 있어서(= 여전히 똑같은 값을 참조하고 있기 때문에)
// 기억하고 searchText를 바꿔줄 수 있는 것 !
const handleSearchText = useCallback(
// debounce 함수가 바로 실행됨
debounce((text) => {
setSearchText(text);
}, 2000),
[]
);
인증 Authentication : 등록된 회원인지 확인하는 절차 (ex. 로그인)
인가(인정하여 허가) Authorization : 특정 리소스에 접근할 수 있는 권한을 확인하는 절차 (ex. 네이버 카페에서 등급에 따라 글을 볼 수 있는 기능)
http 프로토콜 통신의 특징 2가지
쿠키 cookie : 브라우저가 key-value 형태의 텍스트 파일로 저장하고 있는 것
쿠키의 특징
그렇다면 여기서 Origin이란 ? 출처, 여기서는 url의 출처 => url 중에서 'protocol + host + port' 부분을 의미
그렇다면 여기서 CO(origin)RS란 ? Cross Origin Resource Sharing로 다른 출처(= origin)에 리소스 요청을 허용하는 정책
- 기본적으로 브라우저는 보안상의 이유로 Same Origin Policy(SOP)이 원칙이라 같은 출처(= origin)에만 리소스 요청을 허용하는데, 서버와 클라이언트 상호간 CORS 설정을 통해 합의가 되어있다면 예외적으로 API 요청이 가능함
- 또한 쿠키는 클라이언트에서 직접 추가, 수정, 삭제 가능함 => 서버에서 쿠키를 검증하지 않는다면 보안에 매우 취약해짐
이처럼 로그인을 통해 등록된 회원임을 ‘인증’할 때, 서버가 클라이언트 쪽으로 sessionId가 key인 쿠키를 보내고 클라이언트가 ‘인가’가 필요한 데이터를 요청할 때, 클라이언트에서 서버 쪽으로 쿠키가 자동으로 보내짐
세션 : 사용자(= 클라이언트)와 서버 간 연결이 활성화 된 상태 (or 인증이 유지되고 있는 상태)를 의미
물론 http는 비연결성이지만 쿠키와 세션을 이용해 계속적인 인증처리가 자동으로 되면 연결이 활성화 된 상태로 나타날 수 있음
=> 클라이언트는 서버에 요청하여 로그인 성공 (이때 자동으로 쿠키 보내짐) -> 서버는 세션(sessionId) 생성 및 저장 (key-value) -> key(sessionId)를 브라우저에 쿠키로 보내 응답
쿠키-세션 인증(Authentication) 방식 : 쿠키와 세션을 결합해서 클라이언트와 서버간의 통신(ex. 인증과 인가)하는 방식으로 CORS 옵션 중요함
로그인/회원가입 시 세션 인증
인가(Authorization) 필요한 API 요청/응답
+) 참고
토큰 : 클라이언트에서 보관하는 암호화된 인증 정보
(참고로 세션은 서버에서 sessionId를 발급해서 서버에서 보관하는 인증 정보이기 때문에
토큰은 세션처럼 서버에서 사용자의 인증 정보를 보관할 필요가 없기 때문에 서버 부담을 줄여주는 인증 수단)
웹에서 인증 수단으로 사용되는 토큰은 주로 JWT(Json Web Token) 기술로써 요즘 굉장히 많이 사용됨
그렇다면 여기서 JWT의 특징은 ?
JWT 토큰 인증 방식 : JWT 토큰을 통해 클라이언트와 서버간의 통신(ex. 인증과 인가)하는 방식으로 CORS 옵션은 굉장히 중요
로그인/회원가입 시 세션 ‘인증’
‘인가(Authorization)’ 필요한 API 요청/응답
Bearer ${token})을 서버로 보내 get요청을 함 => 이때 리소스 접근 인가를 받기 위해 사용되는 토큰을 Access Token이라고 함
+) Access Token가 브라우저의 쿠키에 들어있는데 이것은 탈취될 가능성이 있다는 것을 의미 => 그래서 Refresh Token 으로 보안 강화
+) 세션 인증 vs 토큰 인증 
split() : 배열의 문자열을 지정한 구분자로 분해하여 배열을 반환하는 배열 메서드
split() mdn 문서
split() 기본형
split()
split(separator)
split(separator, limit)
예시
const str = 'The quick brown fox jumps over the lazy dog.';
const words = str.split(' '); // 구분자로 빈칸
console.log(words[3]); // "fox"
const chars = str.split(''); // 구분자로 빈 값
console.log(chars[8]); // "k"
const strCopy = str.split(); // 구분자가 아예 없는 경우
console.log(strCopy); // ["The quick brown fox jumps over the lazy dog."]
const strCopy = str.split(' ', 3); // 구분자로 빈칸과 배열의 개수 3개
console.log(); // ["The", "quick", "brown"]