자바스크립트 Promise 객체의 내부 작동 방식과 사용 가이드

0

자바스크립트의 프로미스(Promise) 객체는 비동기 작업을 관리하는 데 매우 유용한 도구입니다. 이 글에서는 프로미스의 개념, 작동 방식, 사용법에 대해 자세히 살펴보겠습니다.

프로미스란?

프로미스는 미래의 어느 시점에 완료될 작업을 나타내는 객체입니다. 비동기 코드의 가독성을 높이고, 콜백 지옥(callback hell)을 방지하는 데 큰 도움을 줍니다.

프로미스의 상태

프로미스는 세 가지 상태를 가집니다:

  • Pending(대기): 초기 상태로, 프로미스가 아직 완료되지 않음.
  • Fulfilled(이행): 비동기 작업이 성공적으로 완료됨.
  • Rejected(거부): 비동기 작업이 실패함.

프로미스 생성하기

프로미스 객체는 `Promise` 생성자를 사용해 만들 수 있습니다. 생성자는 함수 하나를 인수로 받는데, 이 함수는 `resolve`와 `reject` 두 가지 매개변수를 가집니다.

const promise = new Promise((resolve, reject) => {
    // 비동기 작업을 수행
    let success = true; // 예시를 위한 변수
    
    if (success) {
        resolve("작업 성공!");
    } else {
        reject("작업 실패!");
    }
});

프로미스 사용법

프로미스는 `then`, `catch`, `finally` 메서드를 통해 사용할 수 있습니다.

then(onFulfilled, onRejected)

프로미스가 이행될 때 호출될 콜백을 지정합니다. `onFulfilled`는 이행 시 호출되고, `onRejected`는 거부 시 호출됩니다.

promise.then(result => {
    console.log(result); // "작업 성공!" 출력
}).catch(error => {
    console.log(error); // "작업 실패!" 출력
});

catch(onRejected)

프로미스가 거부될 때 호출될 콜백을 지정합니다. `then`의 두 번째 인수로 `onRejected`를 전달하는 것과 동일합니다.

promise.then(result => {
    console.log(result);
}).catch(error => {
    console.log(error);
});

finally(onFinally)

프로미스가 이행되든 거부되든 상관없이 항상 실행됩니다. 정리 작업 등을 위해 유용합니다.

promise.finally(() => {
    console.log("작업 완료!");
});

프로미스 체이닝(Promise Chaining)

여러 프로미스를 순차적으로 실행할 때는 프로미스 체이닝을 사용할 수 있습니다.

new Promise((resolve, reject) => {
    setTimeout(() => resolve(1), 1000);
}).then(result => {
    console.log(result); // 1
    return result * 2;
}).then(result => {
    console.log(result); // 2
    return result * 2;
}).then(result => {
    console.log(result); // 4
});

프로미스의 정적 메서드

자바스크립트 프로미스에는 몇 가지 유용한 정적 메서드가 있습니다:

  • [Promise.resolve(value):@b[ 주어진 값으로 이행하는 프로미스를 반환합니다.
  • [Promise.reject(reason):@b[ 주어진 이유로 거부되는 프로미스를 반환합니다.
  • [Promise.all(iterable):@b[ 주어진 모든 프로미스가 이행될 때까지 기다리고, 모든 결과를 배열로 반환합니다.
  • [Promise.race(iterable):@b[ 가장 빨리 완료된 프로미스의 결과를 반환합니다.

프로미스의 내부 동작 방식

프로미스의 내부 작동 방식을 이해하기 위해 중요한 개념 몇 가지를 살펴보겠습니다.

1. Executor 함수

  • `Promise` 객체는 생성 시 `executor` 함수를 인수로 받습니다. 이 함수는 비동기 작업을 수행하며, 두 가지 인수(`resolve`, `reject`)를 가집니다.
  • `resolve` 함수는 비동기 작업이 성공했을 때 호출되며, 프로미스를 이행 상태로 변경합니다.
  • `reject` 함수는 비동기 작업이 실패했을 때 호출되며, 프로미스를 거부 상태로 변경합니다.

2. 상태 전환

  • Pending -> Fulfilled: `resolve` 함수가 호출되면 프로미스는 `Fulfilled` 상태로 전환됩니다.
  • Pending -> Rejected: `reject` 함수가 호출되면 프로미스는 `Rejected` 상태로 전환됩니다.

3. Microtask Queue

  • 프로미스는 비동기 작업을 처리할 때 이벤트 루프의 Microtask Queue를 사용합니다. 이는 일반적인 비동기 작업 (예: `setTimeout`)보다 높은 우선순위를 가집니다.
  • `resolve` 또는 `reject`가 호출되면, 해당 작업은 Microtask Queue에 들어가게 됩니다.

예시로 작동 방식 이해하기

console.log('Script start');

const promise = new Promise((resolve, reject) => {
    console.log('Promise executor');
    resolve('Resolved value');
});

promise.then(value => {
    console.log(value);
});

console.log('Script end');

이 예제는 다음과 같은 순서로 실행됩니다:

  • `Script start` 출력:@b] 자바스크립트 엔진이 코드를 위에서 아래로 실행합니다.
  • 프로미스 생성자 실행:@b] `new Promise`가 호출되고, executor 함수가 실행되어 `Promise executor`가 출력됩니다.
  • `resolve` 호출:@b] `resolve`가 호출되지만, 이 작업은 Microtask Queue에 추가됩니다.
  • `Script end` 출력:@b] 동기 코드가 계속 실행되어 `Script end`가 출력됩니다.
  • Microtask Queue 실행:@b] 동기 코드가 모두 실행된 후, Microtask Queue에 있던 `then` 메서드가 실행되어 `Resolved value`가 출력됩니다.

이처럼 프로미스는 비동기 작업을 처리하고 관리하는 강력한 도구로, 비동기 프로그래밍의 복잡성을 줄이고 가독성을 높이는 데 큰 도움을 줍니다. 프로미스의 내부 작동 방식을 이해하면 비동기 작업을 보다 효과적으로 다룰 수 있습니다.

Leave a Reply