Promise

김콩은·2022년 3월 23일
0

비동기 처리 방법

  1. callback function
    가독성이 나쁘고 에러의 처리가 곤란하며 여러 개의 비동기 처리를 한번에 처리하는 데도 한계가 있다.

  2. Promise
    ES6에서 비동기 처리를 위해 새롭게 도입된 패턴이다. 프로미스는 콜백 패턴이 가진 단점을 보완하며 비동기 처리 시점을 명확하게 표현할 수 있다.


📚 Callback Function


콜백 패턴이 가진 단점을 알아볼 것이다.


💡 콜백 지옥


비동기식 처리 모델(Asynchronous processing model)은 task를 병렬적으로 처리하여 다른 task가 blocking되지 않는(Non-Blocking processing model) 장점이 있다.

이때 처리 순서를 보장하기 위해 여러 개의 콜백 함수가 nesting하면서 복잡도가 높아지는 Callback Hell이 발생하는 단점이 있다.


💡 에러 처리의 한계


try {
  setTimeout(() => { throw new Error('Error!'); }, 1000);
} catch (e) {
  console.log('에러를 캐치하지 못한다..');
  console.log(e);
}

try 블록 내에서 setTimeout 함수가 실행되면 1초 후에 콜백 함수가 실행되고 이 콜백 함수는 예외를 발생시킨다. 하지만 이 예외는 catch 블록에서 캐치되지 않는다. 그 이유는 다음과 같다.

  1. setTimeout (=비동기) 함수는 콜백 함수가 실행되기 전에 즉시 종료되어 콜 스택에서 제거된다.

  2. 이후 tick 이벤트가 발생하면 콜백 함수는 태스크 큐로 이동한 후 콜 스택이 비어졌을 때 콜 스택으로 이동되어 실행된다.

  3. 이떄 setTimeout 함수는 이미 콜 스택에서 제거된 상태이다.

    = 콜백 함수를 호출한 것은 setTimeout 함수가 아니다. 호출자(caller)라면 콜 스택에 존재해야 한다.

  4. 예외는 caller 방향으로 전파된다.

    콜백 함수의 caller는 setTimeout 함수가 아니다.

  5. 콜백 함수 내에서 발생시킨 에러는 catch 블록에서 캐치되지 않아 프로세스는 종료된다.



📚 Promise


Promise 객체는 비동기 작업이 맞이할 미래의 완료 또는 실패와 그 결과 값을 나타낸다.


💡 프로미스의 생성


const promise = new Promise((resolve, reject) => {});

new Promise
생성자 함수를 통해 인스턴스화된다.

executor
new Promise에 전달되는 함수로, new Promise가 만들어질 때 자동으로 실행된다.

resolve / reject
executor의 인자로 전달되는 콜백으로, 자바스크립트 엔진이 미리 정의한 함수이다. 따라서 executor 안 코드만 작성하면 되지만, executor에선 처리 성공 여부에 따라 콜백 중 하나를 반드시 호출해야 한다.

resolve(value): 성공 시 value(결과)와 함께 호출
reject(error): 에러 발생 시 error(에러 객체)와 함께 호출


➖ 프로미스 객체의 프로퍼티



new Promise 생성자가 반환하는 프로미스 객체는 다음과 같은 내부 프로퍼티를 갖는다.

  • state: "pending" ➡ "fulfilled" / "rejected"
  • result: "undefined" ➡ "value" / "error"

state, result 프로퍼티는 내부 프로퍼티이므로 개발자가 직접 접근할 수 없다. .then, .catch, .finally 메서드를 사용하면 접근 가능하다.


💡 프로미스의 state


프로미스는 비동기 처리가 성공(fulfilled)하였는지 또는 실패(rejected)하였는지 등의 상태(state) 정보를 갖는다. executor가 처리 결과에 따라 state를 변화시킨다.

  • fulfilled
    비동기 처리가 수행된 상태 (성공)
    resolve 함수가 호출된 상태

  • rejected
    비동기 처리가 수행된 상태 (실패)
    reject 함수가 호출된 상태

  • settled
    비동기 처리가 수행된 상태 (성공 또는 실패)
    resolve 또는 reject 함수가 호출된 상태

  • pending
    비동기 처리가 아직 수행되지 않은 상태
    resolve 또는 reject 함수가 아직 호출되지 않은 상태


💡 프로미스의 후속 처리 메소드


promise 객체는 executor와 결과나 에러를 받을 처리 메소드를 이어주는 역할을 한다. 처리 결과가 promise 객체의 후속 처리 메소드(.then, .catch, .finally)로 전달되는 것이다.


➖ then


let promise = new Promise(function(resolve, reject) {
  setTimeout(() => resolve("완료!"), 1000);
});

// resolve 함수는 .then의 첫 번째 함수(인수)를 실행한다.
promise.then(
  result => alert(result), // 1초 후 "완료!"를 출력
  error => alert(error) // 실행되지 않음
);

then 메소드는 두 개의 콜백 함수를 인자로 전달 받는다.

  1. 성공 시 호출, 실행 결과를 받는다.
  2. 실패 시 호출, 에러를 받는다.

성공만 ➡ 인수 하나만 전달
실패만 ➡ null 전달 .then(null, errorHandlingFunction)


➖ catch


.catch(errorHandlingFunction)는 .then에 null을 전달한 것과 동일하게 동작한다.

  1. 비동기 처리에서 발생한 에러
  2. then 메소드에서 발생한 에러

➖ finally


성공·실패 여부와 상관없이 프라미스가 처리되면 실행된다. 결과가 어떻든 마무리가 필요할 때 유용하다.

finally는 프라미스 결과를 처리하기 위해 만들어진 게 아니다. 프라미스 결과는 finally를 통과해서 전달된다.

profile
콩딩중

0개의 댓글