모자딥 45장 프로미스

릿·2023년 2월 13일
0

45. 프로미스

45.1 비동기 처리를 위한 콜백 패턴의 단점


45.1.1 콜백 헬

  • 콜백 함수 호출이 중첩되어 복잡도가 높아지는 현상을 콜백 헬이라고 함

45.1.2 에러 처리의 한계

  • 콜백 패턴의 가장 심각한 문제점은 에러 처리가 곤란하는 것
try {
  setTimeout(() => { throw new Error('Error!'); }, 1000);
} catch (e) {
  // 에러를 캐치하지 못함
  console.error('캐치한 에러', e)
}
  • 에러는 호출자 방향으로 전파되고, 콜백 함수를 호출한 건 setTimeout이 아니기 때문에 setTimeout의 콜백함수가 발생시킨 에러는 catch블록에서 캐치되지 않음

45.2 프로미스의 생성


  • Promise생성자 함수를 new연산자와 함께 호출하면 Promise객체를 생성함 (표준 빌트인 객체)
const promise = new Promise ((resolve, reject) => {
  // Promise 함수의 콜백 함수 내부에서 비동기 처리를 수행함
  if (/* 비동기 처리 성공 */) {
    resolve('result');
  } else { /* 비동기 처리 실패 */ 
  	reject('failure reason');
  }
});
  • 프로미스는 현재 비동기 처리가 어떻게 진행되고 있는 지 상태 정보를 가짐
  • 생성된 직후의 프로미스는 기본적으로 pending상태이며, 이후 비동기 처리 결과에 따라 프로미스의 상태가 변경됨
    비동기 처리 성공: resolve함수를 호출해 프로미스를 fulfilled 상태로 변경
    비동기 처리 실패: reject함수를 호출해 프로미스를 rejected 상태로 변경
  • 프로미스는 비동기 처리 상태와 처리 결과를 관리하는 객체

45.3. 프로미스의 후속 처리 메서드


45.3.1 Promise.prototype.then

  • then메서드는 두개의 콜백함수를 인수로 전달받음
  • 첫번째 콜백함수: 비동기 처리가 성공했을 때 호출되는 성공 처리 콜백함수
  • 두번째 콜백함수: 비동기 처리가 실패했을 때 호출되는 실패 처리 콜백함수
// fulfilled
new Promise(resolve => resolve('fulfilled'))
  .then(v => console.log(v), e => console.error(e)); // fulfilled

// rejected
new Promise((_, reject) => reject(new Error('rejected')))
  .then(v => console.log(v), e => console.error(e)); // Error: rejected
  • then메서드는 항상 프로미스를 반환함

45.3.2 Promise.prototype.catch

  • catch메서드는 한 개의 콜백함수를 인수로 전달받고, 프로미스가 rejected상태인 경우만 호출됨
new Promise((_, reject) => reject(new Error('rejected')))
  .catchh(e => console.log(e)); // Error: rejected
  • catch메서드는 항상 프로미스를 반환함

45.3.3 Promise.prototype.finally

  • finally메서드는 한 개의 콜백함수를 인수로 전달받고, 프로미스의 성공, 실패와 상관없이 무조건 한번 호출됨
  • finally메서드는 항상 프로미스를 반환함
new Promise(() => {})
  .finally(() => console.log('finally')); // finally

45.4 프로미스의 에러 처리


  • Promise는 비동기 처리 결과에 대한 후속처리를 then, catch, finally를 사용하여 수행함, 비동기 처리에서 발생한 에러는 then메서드의 두 번째 콜백 함수로 처리할 수 있음

45.5 프로미스 체이닝


  • then, catch, finally 후속 처리 메서드는 언제나 프로미스를 반환하므로 연속적으로 호출할 수 있는데 이를 프로미스 체이닝이라고 함
  • 프로미스는 프로미스 체이닝을 통해 비동기 처리 결과를 전달받아 후속처리를 하므로 콜백 헬이 발생하지 않음

45.6 프로미스의 정적 메서드


45.6.1 Promise.resolve / Promise.reject

  • Promise.resolve메서드와 Promise.reject메서드는 이미 존재하는 값을 래핑하여 프로미스를 생성하기 위해 사용
  • Promise.resolve메서드: 인수로 전달받은 값을 resolve하는 프로미스 생성
// 배열을 resolve하는 프로미스 생성
const resolvedPromise = Promise.resolve([1, 2, 3]);
resolvedPromise.then(console.log); // [1, 2, 3]
  • Promise.reject메서드: 인수로 전달받은 값을 reject하는 프로미스 생성
// 에러 객체를 reject하는 프로미스 생성
const rejectedPromise = Promise.reject(new Error('Error!'));
rejectedPromise.catch(console.log); // Error: Error!

45.6.2 Promise.all

  • Promise.all메서드는 여러 개의 비동기 처리를 모두 병렬 처리할 때 사용함
const requestData1 = () => new Promise(resolve => setTimeout(() => resolve(1), 3000));

const requestData2 = () => new Promise(resolve => setTimeout(() => resolve(2), 2000));

const requestData3 = () => new Promise(resolve => setTimeout(() => resolve(3), 1000));

// 세 개의 비동기 처리를 순차적으로 처리
const res = [];
requestData1()
  .then(data => {
    res.push(data);
    return requestData2();
  })
  .then(data => {
    res.push(data);
    return requestData3();
  })
  .then(data => {
    res.push(data);
    console.log(res); // [1, 2, 3] => 약 6초 소요
  })
  .catch(console.error);
  
// Promise.all을 사용하는 경우
Promise.all([requestData1(), requestData2(), requestData3()])
  .then(console.log) // [1, 2, 3] => 약 3초 소요
  .catch(console.error);
  • 모든 프로미스가 fulfilled상태가 되면 resolve된 처리 결과를 모두 배열에 저장해 새로운 프로미스를 반환함

45.6.3 Promise.race

  • Promise.race메서드는 가장 먼저 fulfilled상태가 된 프로미스 결과를 resolve하는 새로운 프로미스를 반환함
Promise.race([
  new Promise(resolve => setTimeout(() => resolve(1), 3000)), // 1
  new Promise(resolve => setTimeout(() => resolve(2), 2000)), // 2
  new Promise(resolve => setTimeout(() => resolve(3), 1000)), // 3
])
  .then(console.log) // 3
  .catch(console.log);

45.6.4 Promise.allSettled

  • Promise.allSettled메서드는 전달 받은 프로미스가 모두 settled상태가 되면 처리 결과를 배열로 반환함
Promise.allSettled([
  new Promise(resolve => setTimeout(() => resolve(1), 2000)),
  new Promise((_, reject) => setTimeout(() => reject(new Error('Error')), 1000)),
]).then(console.log);

45.7 마이크로태스크 큐


setTimeout(() => console.log(1), 0);

Promise.resolve()
  .then(() => console.log(2))
  .then(() => console.log(3))
  • console이 2 -> 3 -> 1순으로 출력됨, 프로미스의 후속 처리 메서드의 콜백함수는 마이크로 태스크 큐에 저장되기 때문임
  • 마이크로태스크 큐는 태스크 큐와는 별개로, 태스크큐보다 우선순위가 높음

45.8 fetch


  • fetch함수는 HTTP 요청 전송 기능을 제공하는 클라이언트 사이드 Web API임
  • fetch함수에는 HTTP 요청을 전송할 URL과 HTTP 요청 메서드, HTTP 요청 헤더, 페이로드 등을 설정한 객체를 전달함
const promise = fetch(url, [, options])
  • fetch함수는 HTTP 응답을 나타내는 Response객체를 래핑한 Promise객체를 반환함
fetch('https://jsonplaceholder.typicode.com/todos/1')
  .then(response => console.log(response));
  • fetch함수가 반환하는 프로미스는 HTTP에러가 발생해도 에러를 reject하지 않고 불리언 타입의 ok상태를 false로 설정한 Response객체를 resolve함, 네트워크 장애나 CORS에러에 의해 요청이 완료되지 못한 경우에만 프로미스를 reject함
profile
항상 재밌는 뭔가를 찾고 있는 프론트엔드 개발자

0개의 댓글