콜백 함수(callback function)

JavaScript는 비동기 처리를 위해 콜백 함수를 사용하곤 했는데, 이 전통적인 콜백 패턴은 몇 가지 한계점이 있었다.
1. callback hell로 인해 가독성이 나쁘다.
2. 비동기 처리 중 발생한 에러를 처리하기 어렵다.
3. 여러 개의 비동기 처리를 한번에 처리하기 어렵다.

➡️ ES6에서 비동기 처리를 위한 새로운 패턴으로 Promise를 도입했다.
Promise는 전통적인 콜백 패턴이 가진 단점을 보완하며, 비동기 처리 시점을 명확하게 표현할 수 있다는 장점이 있다.

Promise

: JavaScript의 비동기 처리에 사용되는 객체

Promise 생성하는 법

Promise는 Promise 생성자 함수를 이용해 instance를 생성한다.

  • 이때 Promise 생성자 함수는 비동기 작업을 수행하는 콜백 함수를 매개변수로 받으며, 이 콜백 함수는 resolve 함수reject 함수를 매개변수로 받는다.
const promise = new Promise((resolve, reject) => {});

예시)

const promise = new Promise((resolve, reject) => {
	if(비동기 작업 수행이 성공했다면..) {
    	resolve('결과를 표시합니다.');
    } else { // 비동기 작업 수행이 실패했다면..
    	reject('실패 원인을 표시합니다.');
    }
});	

Promise 프로퍼티

: Promise 객체는 2개의 프로퍼티를 갖는다.

1. state

: 비동기 처리가 성공했는지 실패했는지에 대한 상태

2. result

: resolve/reject 함수로부터 전달받은 값

상태의미구현
pending비동기 처리가 수행되지 않은 상태아무 함수도 호출되지 않은 상태
fulfilled비동기 처리가 수행된 상태(성공)resolve 함수가 호출된 상태
rejected비동기 처리가 수행된 상태(실패)reject 함수가 호출된 상태
settled비동기 처리가 수행된 상태(성공/실패)resolve/reject 함수가 호출된 상태

pending

: Promise 생성자 함수의 인자로 전달받은 콜백 함수는 비동기 처리 작업을 수행하는데, 작업을 수행하기 전의 대기 상태이다.

  • state : pending
  • result : undefined
const printHello = new Promise((resolve, reject) => { });

printHello;


fulfilled

: 콜백 함수가 수행한 비동기 작업이 성공한 경우, Promise의 상태는 fulfilled 상태가 되고 콜백 함수의 인자로 전달받은 resolve 함수를 호출한다.

  • state : resolve
  • result : resolve() 함수로부터 전달받은 값
const printHello = new Promise((resolve, reject) => {
  let a = 1 + 1;
  if(a === 2) {
    resolve('이행되었습니다.'); 
  } else {
    reject('거절되었습니다.');
  }
});

printHello;


rejected

: 콜백 함수가 수행한 비동기 작업이 실패한 경우, Promise의 상태는 rejected 상태가 되고 콜백 함수의 인자로 전달받은 reject 함수를 호출한다.

  • state : rejected
  • result : reject 함수로부터 전달받은 값
const printHello = new Promise((resolve, reject) => {
  let a = 1 + 99;
  if(a === 2) {
    resolve('이행되었습니다.'); 
  } else {
    reject('거절되었습니다.');
  }
});

printHello;


Promise Chaining

.then()

Promise.prototype.then() : Promise를 반환하므로 메서드 체이닝을 할 수 있다.

const a = new Promise((resolve, reject) => {
	resolve(1);
})
// 이때 프로미스 객체는 state : fulfilled, result : 1 이다.

a.then((num) => num + 1) // state : fulfilled, result : 2
 .then((num) => num + 1) // state : fulfilled, result : 3
 .then((num) => num + 1) // state : fulfilled, result : 4

.catch()

Promise.prototype.catch : Promise를 반환하며 메서드 체이닝을 할 수 있다.
에러가 난 경우 실행되는 메서드이다.

const printHello = new Promise((resolve, reject) => {
  let a = 1 + 99;
  if(a === 2) {
    resolve('이행되었습니다.'); 
  } else {
    reject('거절되었습니다.');
  }
});

printHello
  .then((msg) => {
    console.log('then : ' + msg)
  })
  .catch((msg) => {
    console.log('catch : ' + msg)
  });
// catch : 거절되었습니다.

Promise.all()

Promise.all([prms1, prms2...]) : 여러 개의 Promise를 한 번에 처리하는 메소드

  • 배열 내 모든 Promise의 이행(또는 첫 번째 거부)을 기다리고, 결과를 배열로 반환한다.
  • Promise.all()에 전달된 배열 안의 Promise들의 순서대로 결과로 반환되는 배열의 요소의 순서가 정해진다.
  • 입력 값으로 들어온 Promise 중 하나라도 거부되면 Promise.all()즉시 거부되며 catch() 메소드를 실행한다.
Promise.all([
  new Promise(resolve => setTimeout(() => resolve(1), 3000)),
  new Promise(resolve => setTimeout(() => resolve(2), 2000)),
  new Promise(resolve => setTimeout(() => resolve(3), 1000))
])
.then((result) => console.log(result)); 
// 프라미스 전체가 처리된 후(3초 후) [1, 2, 3]이 반환된다.

위 코드의 각 Promise를 변수에 할당하여 더 간단하게 작성해보면, 아래처럼 작성할 수 있다.

const one = new Promise((resolve) => setTimeout(() => resolve(1), 3000));
const two = new Promise((resolve) => setTimeout(() => resolve(2), 2000))
const three = new Promise((resolve) => setTimeout(() => resolve(3), 1000));

Promise.all([one, two, three])
  .then((result) => console.log(result));
// [1, 2, 3]

Promise Hell

: 여러 개의 Promise가 계속해서 중첩(nesting)되어 코드가 복잡해지고, 가독성이 떨어지는 것

❔ 학습 후 궁금한 점

  • Promise.all() 에서 Promise들 중 하나라도 에러가 발생하면, 에러 어디서 발생한 건지 어떻게 아는지?
  • Promise hell의 개념을 제대로 이해하지 못했다 😂

이 글은 아래 링크를 참고하여 작성한 글입니다.
https://poiemaweb.com/es6-promise

profile
개발 공부 기록 블로그

0개의 댓글