Promise (Macro/Micro task)
프로미스(Promise)
자바스크립트는 비동기 처리를 위해 콜백 함수를 사용함
하지만 콜백을 남용하게 되면 흔히 말하는 콜백 지옥에 빠질 수 있음
자바스크립트는 콜백 함수의 단점을 보완하며 효율적인 비동기 처리를 위해서 ES6부터 Promise 도입
▶ Promise 객체
어떤 작업에 관한 '상태 정보'를 갖고 있는 객체
작업의 결과가 promise 객체에 저장됨(promise 객체를 보면 작업이 성공했는지, 실패했는지 알 수 있음)
new Promise((resolve,reject)=>{})
Promise의 Callback 함수는 두가지 인자를 받음
- resolve 메소드: Promise 객체의 골백함수가 제대로 수행(fulfilled) 되었을 때 호출
- reject 메소드: Promise 객체의 골백함수가 거부(rejected) 되었을 때 호출
Promise 객체 3가지 상태([[PromiseStatus]])
- 성공(fulfilled): 비동기 처리가 완료되어 프로미스가 결과 값을 반환한 상태
- 객체가 fulfilled 상태가 되면 promise 객체는 작업의 성공 결과도 함께 갖게 됨
- 실패(rejected): 비동기 처리가 실패하거나 오류가 발생한 상태
- 객체가 rejected가 되면 promise 객체는 작업의 실패 이유에 관한 정보도 함께 갖게 됨
- 대기(pending): 비동기 처리 로직이 완료되지 않은 상태
pending 상태에서 한번 fulfilled/rejected 상태가 되면 다시 다른 상태를 가질 수 없음
또한 [[PromiseValue]]의 값은 resolve, reject에서 호출되어 인자로 들어가는 값들이 들어감
두 상태(fulfilled, rejected)일 때는 각각의 메소드에서 받은 값이 들어가있
pending 일때는 undefined로 초기화되어 있음
Promise의 후속 처리 메소드
- then: promise 객체가 fulfilled 상태가 되면 실행할 콜백함수를 등록
- catch: promise 객체가 rejected 상태가 되면 실행할 콜백함수를 등록
- finally: 어떤 작업의 성공, 실패 여부와 상관없이 항상 실행하고 싶은 콜백함수를 등록
Promise 정적 메소드
- Promise.resolve: 인자값을 래핑하여 프로미스를 반환(fufilled)
- Promise.reject: 인자값을 래핑하여 프로미스를 반환(rejected)
- Promise.all: 여러 비동기 처리를 병렬로 실행. 모든 프로미스가 fulfilled 되면 결과를 배열로 반환하며, 하나라도 rejected 되면 즉시 종료
- Promise.allSettled: 여러 비동기 처리를 병렬로 실행하며, 모든 프로미스가 완료될 때까지 기다림. 각 프로미스의 결과를 객체 배열로 반환
- Promise.any: 가장 먼저 fulfilled 되는 프로미스를 반환. 모든 프로미스가 rejected 될 경우, AggregateError를 발생시킴
- Promise.race: 가장 먼저 처리된 (fulfilled 또는 rejected) 프로미스를 반환
Microtasks and (Macro)tasks
이벤트 루프에서 Task Queue(Qallback Queue)는 안에 두개의 큐가 있가 있음
두개의 큐는 micro task queue와 (macro)task queue(통상적으로 task queue라고 부름)
- Micro task를 콜백에 넣는 함수: process.nextTick , Promise , Object.observe , MutationObserver
- (Macro)task를 콜백에 넣는 함수: setTimeout , setInterval , setImmediate, requestAnimationFrame, I/O(click, srcoll ...) , UI 렌더링
- 콜스택에 있는 모든 함수가 실행 되면서 스택에서 빠져나옴
- 호출 스택이 비어있으면, 대기 중인 마이크로 테스크가 콜스택으로 하나씩 들어가고 실행됨
- 호출 스택과 마이크로 스택이 모두 비워지게되면 이벤트 루프는 매크로 태스크 큐의 남은 작업을 콜스택으로 넣어서 실행하게 됨
마이크로 태스크 큐의 task 들은 매크로 테스크 큐 보다 우선 순위가 높음
// 1. 실행
console.log('script start')
// 2. call stack 메소드 콜스택에 추가
// setTimeOut이 실행되면 콜백함수가 Web Api에 추가됨
// 타이머가 실행되고 타이머가 완료되면 macrotask queue로 콜백함수가 넘어감
setTimeout(function() {
// 7. call stack과 microtask queue가 다 비어졌으면
// macrotask queue를 call stack에 옮기고 실행
console.log('setTimeout')
}, 0)
// 3. Promise.resolve()가 콜스택에 추가되고 Promise.then() 객체 반환
Promise.resolve('Promise!')
// 4. then의 콜백함수가 microtask queue에 전달
// 6. microtask queue에서 콜스택으로 옮기고 실행
.then(res => console.log(res))
// 5. 실행
console.log('script end')
위를 보면 Promise가 setTimeout과는 다르게 Web API를 거치지 않는데
Promise는 자바스크립트 표준 API로 웹 브라우저와 소통하기 위한 프로그래밍 인터페이스인 Web API에는 속하지 않음
그래서 Call Stack에서 Web API를 거치지 않고 Microtask Queue(res=>console.log(res))로 바로 이동함
또한 setTimeout도 setTimeout 자체가 Web API로 가는것이 아니라 두가지 정보를 보냄(타이머와 콜백함수)
Reference
[JavaScript] Promise 객체 한 번에 이해하자!
비동기 Task Queue (Macrotask Queue 와 Microtask Queue) 에 대해서