JavaScript
20210720 JavaSciprt DeepDive 16 : 타이머, 디바운스, 스로틀, 비동기 프로그래밍(블로킹, 이벤트 루프, 태스크 큐, 콜 스택, 힙), Ajax, JSON, XMLHttpRequest, REST API
JavaScript Deep Dive 16
📄 용어 및 중요사항 정리
타이머
호출 스케줄링(scheduling a call)
:- 함수를 명시적으로 호출하지 않고 일정 시간이 경과된 이후에 호출되도록 함수 호출을 예약하는 것
타이머 함수
: 스케줄링을 구현하게 도와주는 함수로 전역 객체의 메서드인 호스트 객체 임- setTimeout, setInterval
- 비동기 처리 방식으로 동작 함
싱글 스레드(single thread)
: JS 엔진은 단 하나의 실행 컨텍스트 스택을 갖기 때문에 두 가지 이상의 태스크를 동시에 실행 불가함
타이머 함수
setTimeout(callback[, delay, param1, param2, ...])
- 두번째 인수로 전달받은 시간(delay)으로 단 한번 첫번째 인수로 전달 받은 콜백(callback)을 호출하는 타이머 생성
- callback : 시간 만료후 실행될 callback 함수
- delay : 타이머 만료시간 (ms 단위), 생략시 기본값 0
- delay 시간이 콜백함수가 그 시간에 호출되는 것을 보장하지 않음
- 4ms 이하일 경우 최소 지연 시간 4ms
- params : 호출 스케줄링된 콜백 함수에 전달해야 할 인수가 존재하는 경우 전달할 인수
return
: 생성된 타이머를 식별할 수 있는 고유한 타이머 id 반환- 반환된 id는 clearTimeout에서 사용됨
- 브라우저 환경: Number, Node.js: Object
- 두번째 인수로 전달받은 시간(delay)으로 단 한번 첫번째 인수로 전달 받은 콜백(callback)을 호출하는 타이머 생성
clearTimeout(setTimeoutId)
: setTimeout id를 인수로 받아서 해당 setTimeout 타이머의 호출 스케줄링을 취소 함
setInterval(callback[, delay, param1, param2, ...])
- 두번째 인수(delay)로 받은 시간 마다 반복하여 첫번째 인수로 전달 받은 콜백(callback)을 호출하는 타이머 생성
- callback, delay, params, return은 setTimeout과 같음
clearInterval(setIntervalId)
: setInterval id를 인수로 받아서 해당 setInterval 타이머의 호출 스케줄링을 취소 함
디바운스와 스로틀
디바운스, 스로틀
: 짧은 시간 간격으로 연속해서 발생하는 이벤트를 그룹화해서 과도한 이벤트 핸들러의 호출 방지하는 프로그래밍 기법- 연속 발생 이벤트 : scroll, resize, input, mousemove 등
디바운스(debounce)
:- 짧은 시간 간격으로 발생하는 이벤트를 그룹화해서 마지막에 한 번만 이벤트 핸들러가 호출되도록 함
- 짧은 시간 간격으로 이벤트가 연속 발생시, 이벤트 핸들러 호출하지 않다가 일정 시간 동안 이벤트가 발생하지 않으면 핸들러가 한번만 호출되도록 함
- 클로저를 활용해서, 타이머 id를 기억하여 타이머가 생성되었는지 체크하여 새로운 요청시 기존 타이머 취소하고 새롭게 타이머를 만드는 방식
- resize 이벤트 처리, 입력 필드 자동완성 UI, 버튼 중복 클릭 방지
- 라이브러리 : Underscore / Lodash debounce 함수 사용 권장
const debounce = (callback, delay) => {
let timerId;
return (event) => {
if (timerId) clearTimeout(timerId);
timerId = setTimeout(callback, delay, event);
};
};
// callback : 처리할 일(이벤트 핸들러)
// delay : 이벤트 핸들러를 호출하는데 계속 새로 설정하는 시간(요청을 한번만 인식할 시간)
스로틀(throttle)
:- 짧은 시간 간격으로 연속해서 발생하는 이벤트를 그룹화해서 일정 시간 단위로 이벤트 핸들러가 호출되도록 호출 주기를 만듦
- delay가 경과하기 이전에 이벤트 발생시, 아무것도 하지 않고 delay 시간 경과시 이벤트 발생시 콜백함수 호출하고 새로운 타이머 재설정
- 시간 간격으로 콜백 함수가 호출됨
- scroll 이벤트 처리, 무한 스크롤 UI 구현
- 라이브러리 : Underscore / Lodash throttle 함수 사용 권장
const throttle = (callback, delay) => {
let timerId;
return (event) => {
if (timerId) return;
timerId = setTimeout(
() => {
callback(event);
timerId = null;
},
delay,
event
);
};
};
비동기 프로그래밍
싱글 스레드
: JS 엔진과 같이 한번에 하나의 태스크만 실행할 수 있는 동작 방식동기 처리(synchronous)
: 앞선 태스크가 종료 할때 까지 이후 태스크가 대기하는 방식태스크(task)
: 실행 중인 실행 컨텍스트를 제외한 실행 대기 중인 모든 실행 컨텍스트- 현재 실행중인 실행 컨텍스트가 스택에서 제거되면, 비로소 태스크의 실행 컨텍스트가 실행 됨
블로킹(blocking)
: 싱글 스레드 방식에 의해서, 앞의 긴시간이 걸리는 작업의 경우 뒤에 있는 함수가 실행 중단이 되는 것- 태스크 실행 순서가 보장 됨
비동기 처리(asynchronous)
: 현재 실행 중인 태스크가 종료 되지 않은 상태라 해도 다음 태스크를 곧바로 실행하는 방식- 태스크 실행 순서가 보장되지 않음
콜백 패턴
: 비동기 처리를 수행하는 비동기 함수의 전통적인 패턴 -> 콜백 헬을 발생시킴- 콜백 헬 : 가독성 나쁨, 예외처리 곤란, 한번에 여러개의 비동기 처리 곤란
- 비동기 함수 :
- setTimeout, setInterval, HTTP 요청, 이벤트 핸들러 (브라우저에서 제공하는 API이기 때문에, 비동기가 가능함)
이벤트 루프와 태스크 큐
멀티 스레드
: 브라우저 ,싱글 스레드
: 자바스크립트 엔진- 비동기 처리는 브라우저에서 제공하는 엔진과 자바스크립트 엔진의 병렬적 처리 덕분에 가능케 함
- 자바스크립트 엔진
- 비동기 함수의 콜백의 평가와 실행 담당
콜 스택
: 실행 컨텍스트가 추가되고 제거되는 스택 자료 구조(실행 컨텍스트 스택)힙
: 객체가 저장되는 메모리 공간(실행 컨텍스트가 객체를 참조함)- 객체가 저장되어 있기 때문에 메모리가 동적 할당 되어 메모리 공간이 구조화 되어 있지 않음
- 브라우저 환경, Node.js 환경
- 호출 스케줄링을 위한 타이머설정, 콜백 함수의 등록은 브라우저 또는 Node.js에서 담당
태스크 큐(task queue, event queue, callback queue)
- 비동기 함수의 콜백 함수, 이벤트 핸들러가 일시적으로 보관되는 영역
이벤트 루프
:- 브라우저에 내장되어 있는 기능 중 하나
- 콜 스택에 현재 실행중인 실행 컨텍스트가 있는지, 태스크 큐에 대기 중인 함수가 있는지 반복해서 확인함
- 콜 스택이 비어 있고, 태스크 큐에 대기중인 함수 존재시 이벤트 루프가 선입선출(FIFO) 방식으로 태스크 큐에 대기중인 함수를 콜 스택으로 이동시킴
- 비동기 처리 과정
- 전역 실행 컨텍스트 생성 -> 콜 스택 푸시
- 비동기 처리 함수 호출 -> 비동기 처리 함수 실행 컨텍스트 생성 -> 콜 스택 푸시
- 비동기 처리 함수 실행 -> 콜백 함수 호출 스케줄링 -> 함수 종료(콜 스택 팝)
- 병렬 처리
- 병렬01 : 타이머 설정후 타이머 만료시 브라우저가 콜백 함수를 태스크 큐에 푸시 -> 콜백 함수 대기
- 병렬02 : 다른 함수 호출, 실행 컨텍스트 생성 -> 콜 스택 푸시 (현재 실행중인 실행 컨텍스트가 됨) -> 함수 종료(콜 스택 팝)
- 전역 코드 실행 종료 -> 전역 실행 컨텍스트 콜 스택에서 팝
- 콜 스택이 비어 있음을 이벤트 루프가 감지 -> 콜백함수 실행 컨텍스트 생성 후 태스크 큐의 콜백함수 콜스택에 푸시 -> 콜백 종료(콜 스택 팝)
Ajax, JSON, XMLHttpRequest
Ajax
: JS를 사용하여 브라우저가 서버에게 비동기 방식으로 데이터를 요청후 서버 응답을 받아 웹페이지를 동적으로 갱신하는 프로그래밍 방식- WebAPI인 XMLHttpRequest 객체 기반 동작
전통적인 서버 통신의 단점
- 변경할 필요가 없는 부분까지 포함된 완전한 HTML을 서버로 부터 매번 다시 받아 불필요한 데이터 통신 발생
- 변경할 필요 없는 부분까지 다시 렌더링
- 서버 응답이 있을 때 까지 블로킹 됨
Ajax 통신 장점
- 변경에 필요한 부분만 전송받아 변경, 불필요한 데이터 통신 발생 X
- 변경이 없는 부분은 렌더링 하지 않음 -> 화면 공백 현상 X
- 비동기 방식 동작으로 인해 서버에게 요청 후 블로킹 발생 X
JSON
: 클라이언트와 서버 간의 HTTP 통신을 위한 텍스트 데이터 포맷(언어 독립형 데이터 포맷)- 표기방식 : JS 객체 리터럴과 유사, 키-값 구조의 순수한 텍스트
- 큰따옴표 사용 의무 O
JSON.stringify(object, filter함수, indent)
: 객체, 배열을 JSON 포맷의 문자열로 변환(직렬화)- object : 직렬화할 객체, 배열 대상
- filter함수 : 객체의 각 key-value를 인수로 받아 함수가 처리하여 return 하는 value를 직렬화의 item으로 함
- indent : 직렬화한 결과가 indent 숫자를 무엇으로 가질지 설정
return
: 변환된 문자열
JSON.parse(json)
: JSON 포맷의 문자열을 객체, 배열로 변환함 (역직렬화)- json : 직렬화한 JSON 문자열
return
: JSON 문자열을 변화한 배열 또는 객체
- 표기방식 : JS 객체 리터럴과 유사, 키-값 구조의 순수한 텍스트
XMLHttpRequest
- JS를 사용하여 HTTP 전송할때 필요한 XMLHttpRequest 객체(Web API)
new XMLHttpRequest()
: XMLHttpRequest 객체 생성자 함수XMLHttpRequest 객체 프로토타입 프로퍼티
- readyState : HTTP 요청의 현재 상태를 나타내는 정수
- UNSENT(0), OPENED(1), HEADERS_RECEIVED(2), LOADING(3), DONE(4)
- status : HTTP 응답 상태(HTTP 상태 코드)
- statusText : HTTP 응답 메세지를 나타내는 문자열
- responseType : HTTP 응답 타입 (document, json, text, blob, arraybuffer ...)
- response : HTTP 응답 몸체
- responseText : 서버가 전송한 HTTP 요청에 대한 응답 문자열
- readyState : HTTP 요청의 현재 상태를 나타내는 정수
XMLHttpRequest 객체의 이벤트 핸들러 프로퍼티
- onreadystatechange : readyState 프로퍼티 값이 변경된 경우
- onloadstart : HTTP 요청에 대한 응답을 받기 시작한 경우
- onprogress : HTTP 요청에 대한 응답을 받는 도중 주기적으로 발생
- onabort : abort 메서드에 의해 HTTP 요청이 중단된 경우
- onerror : HTTP 요청에 에러가 발생한 경우
- onload : HTTP 요청이 성공적으로 완료한 경우
- ontimeout : HTTP 요청 시간이 초과한 경우
- onloadend : HTTP 요청이 완료된 경우(성공, 실패 시 발생)
XMLHttpRequest 객체 메서드
- open : HTTP 요청 초기화
- send : HTTP 요청 전송
- abort : 이미 전송된 HTTP 요청 중단
- setRequestHeader : 특정 HTTP 요청 헤더의 값을 설정
- getRequestHeader : 특정 HTTP 요청 헤더의 값을 문자열로 반환
XMLHttpRequest 객체 정적 프로퍼티
- UNSENT : 값 0, open 메서드 호출 이전
- OPENED : 값 1, open 메서드 호출 이후
- HEADERS_RECEIVED : 값 2, send 메서드 호출 이후
- LOADING : 값 3, 서버 응답중(응답 데이터 미완성 상태)
- DONE : 값 4, 서버 응답 완료
HTTP 요청 전송
- XMLHttpRequest.prototype.open 메서드로 HTTP 요청 초기화
- 필요에 따라 XMLHttpRequest.prototype.setRequestHeader 메서드로 특정 HTTP 요청의 헤더값 설정
- XMLHttpRequest.prototype.send 메서드로 HTTP 요청 전송
XMLHttpRequest.prototype.open(method, url[, async])
- method : HTTP 요청 메서드("GET", "POST", "PUT", "DELETE" 등)
- url : 요청을 전송할 URL
- async : 비동기 요청 여부, 옵션(기본값 true)
HTTP 요청 메서드
HTTP 요청 메서드 | 종류 | 목적 | 페이로드 |
---|---|---|---|
GET | index/retrieve | 모든/특정 리소스 취득 | X |
POST | create | 리소스 생성 | O |
PUT | replace | 리소스의 전체 교체 | O |
PATCH | modify | 리소스의 일부 수정 | O |
DELETE | delete | 모든/특정 리소스 삭제 | X |
XMLHttpRequest.prototype.send(payload)
- open 메서드로 초기화된 HTTP 요청을 서버에 전송
- GET 요청 메서드 : URL 일부분인 쿼리 문자열로 서버에 전송
- GET 메서드인 경우, payload 인수는 무시됨 요청 몸체 null 설정
- POST 요청 메서드 : 페이로드를 요청 몸체에 담아 전송
- payload가 객체인 경우 반드시 직렬화 하여 전달해야 함
XMLHttpRequest.prototype.setReauestHeader(헤더 종류, 헤더 값)
- 특정 HTTP 요청의 헤더 값을 설정
'Content-type'
: 요청 몸체에 담아 전송할 데이터의 MIME 타입 정보 표현MIME(Multipurpose Internet Mail Extensions)
: 웹을 통해서 여러 형태의 파일 전달할 때 쓰임- MIME type :
- text - 서브타입 : text/plain, text/html, text/css, text/javascript
- application - 서브타입 : application/json, application/x-www-form-urlencode
- multipart - 서브타입 : multipart/formed-data
'Accept'
: 서버가 응답할 데이터의 MIME 타입 지정- 클라이언트가 요청시 Content-type은 클라이언트가 전송하는 데이터의 타입, Accept는 서버가 전송하는 데이터의 타입
HTTP 응답 처리
- send메서드를 통해서 HTTP요청 후 서버 응답이 올 때를 캐치해야 함
- XMLHttpRequest 객체의 이벤트 핸들러 프로퍼티에 이벤트 핸들러를 할당
- 방법01 : 이벤트(onreadystatechange) 발생을 캐치하여 이벤트 핸들러 함수로 HTTP 응답 처리 함
- 이벤트 핸들러 함수에서, readyState 값을 확인 -> 요청 성공 완료 상태를 확인
- status 값을 확인 -> 정상인지 에러인지 확인
- 방법02 : 이벤트(onload) 발생을 캐치핳여 이벤트 핸들러 함수로 HTTP 응답 처리함
- readyState 값을 확인할 필요 없음, onload 발생은 요청이 성공적으로 완료 했을때 발생하므로
- 핸들러 함수 내부에서 status 값을 확인하여 error와 응답data를 구분하여 어떻게 처리할지 설정
const xhr = new XMLHttpRequest();
xhr.open("GET", "https://jsonplaceholder.typicode.com/todos/1");
xhr.send();
xhr.onload = () => {
if (xhr.status === 200) {
console.log(JSON.parse(xhr.response));
} else {
console.log("Error", xhr.status, xhr.statusText);
}
};
REST API
REST(REpresenational State Transfer)
: HTTP 기반으로 클라이언트가 서버의 리소스에 접근하는 방식을 규정한 아키텍처
REST API
: REST를 기반으로 서비스 API를 구현한 것을 의미
REST API 구성
- 자체 표현 구조로 구성되어 REST API만으로 HTTP 요청의 내용을 이해할 수 있음
- 자원 : 자원 -> URI(엔드 포인트)
- 행위 : 자원에 대한 행위 -> HTTP 요청 메서드
- 표현 : 자원에 대한 행위의 구체적 내용 -> 페이로드
REST API 설계 원칙
- URI는 리소스를 표현해야 함
- 리소스 식별 이름은 동사보다 명사를 사용
- 행위에 대한 정의는 HTTP 요청 메서드로 표현해야 함
- 리소스에 대한 행위는 URI가 아니라 HTTP 요청 메서드로 표현
- URI는 리소스를 표현해야 함