JS

Promise (Macro/Micro task)

Hyeon_E 2024. 6. 12. 19:10

프로미스(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 렌더링

 

 

  1. 콜스택에 있는 모든 함수가 실행 되면서 스택에서 빠져나옴
  2. 호출 스택이 비어있으면, 대기 중인 마이크로 테스크가 콜스택으로 하나씩 들어가고 실행됨
  3. 호출 스택과 마이크로 스택이 모두 비워지게되면 이벤트 루프는 매크로 태스크 큐의 남은 작업을 콜스택으로 넣어서 실행하게 됨

마이크로 태스크 큐의 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 객체 한 번에 이해하자!

프로미스(Promise) 바로 알기

비동기 Task Queue (Macrotask Queue 와 Microtask Queue) 에 대해서

프로미스 관련 소소한 궁금증들