Skip to main content

1.3 Promise()


1. 개요

Promise는 자바스크립트에서 비동기 작업의 완료(또는 실패)를 나타내는 객체이다.
미래에 완료될 값을 나타내며, 동기 코드처럼 .then().catch()로 결과를 처리할 수 있다.


2. 상태

Promise는 세 가지 상태를 가진다:

  1. Pending(대기) – 아직 완료되지 않은 초기 상태
  2. Fulfilled(이행) – 비동기 작업이 성공적으로 완료됨
  3. Rejected(거부) – 비동기 작업이 실패함

Promise는 비동기 처리가 성공(fulfilled) 또는 실패(rejected) 등의 상태 정보를 갖게된다. resolve 함수가 호출 된경우 성공된 상태이고, reject 함수가 호출 된 경우 실패 상태이게 된다.

아래 예제를 보면 promise 라는 이름의 전역 변수에 프로미스를 할당 하였고 그 안에는 1 + 1 이 2라면 resolve 함수를 호출하고 아니면 reject 함수를 호출하도록 구현했다. 그 다음 프로미스의 후속 처리 메소드인 then(), catch()를 통해 비동기 처리 결과 메세지를 전달받아 처리한다.

const promise = () => new Promise((resolve, reject) => {
    let a = 1 + 1

    if(a == 2) {
        resolve('success')
    } else {
        reject('failed')
    }
})

promise().then((message) => {
    console.log('This is in the then ' + message)
}).catch((message) => {
    console.log('This is in the catch' + message)
})

3. 생성

const promise = new Promise((resolve, reject) => {
    // 비동기 작업 수행
    if (/* 성공 */) {
        resolve("성공 결과");
    } else {
        reject("실패 이유");
    }
});
  • resolve(value) – 작업 성공 시 호출, 결과 전달
  • reject(reason) – 작업 실패 시 호출, 이유 전달

4. 사용 방법

프로미스로 구현된 비동기 함수를 호출하는 측에서는 프로미스 객체의 후속 처리 메소드(then, catch)를 통해 비동기 처리 결과 또는 에러 메세지를 전달받아 처리한다.

then

  • then 메소드는 두 개의 콜백 함수를 인자로 전달 받는다.
  • 첫 번째 콜백 함수는 성공(fulfilled, resolve 함수가 호출된 경우)시에 실행된다.
  • 두 번째 콜백 함수는 실패(rejected, reject 함수가 호출된 경우)시에 실행된다.
  • then 메소드는 기본적으로 프로미스를 반환한다.

catch

  • catch 메소드는 비동기 처리 혹은 then 메소드 실행 중 발생한 에러(예외)가 발생하면 호출된다.
  • catch 메소드 역시 프로미스를 반환한다.
promise
    .then(result => {
        console.log("작업 성공:", result);
    })
    .catch(error => {
        console.error("작업 실패:", error);
    })
    .finally(() => {
        console.log("작업 완료 (성공/실패 상관없이)");
    });
  • .then() – 성공 처리
  • .catch() – 실패 처리
  • .finally() – 성공/실패 상관없이 항상 실행

5. 에러처리

프로미스를 이용한 에러 처리 방법은 두 가지가 있다.

첫 번째 방법은 then 메소드의 두 번째 인자로 예외를 처리하는 방법이다.

const promise = () => new Promise((resolve, reject) => {
    let a = 1 + 1

    if(a == 3) {
        resolve('success')
    } else {
        reject('failed')
    }
})

promise().then((message) => {
    console.log('This is in the then ' +  message)
}, (error) => {
    console.log('This is in the then ' +  error)
})
This is in the then failed

두 번째 방법은 catch 메소드를 이용하여 예외를 처리하는 방법이다.

const promise = () => new Promise((resolve, reject) => {
    let a = 1 + 1

    if(a == 3) {
        resolve('success')
    } else {
        reject('failed')
    }
})

promise().then((message) => {
    console.log('This is in the then ' +  message)
}).catch((error) => {
    console.log('This is in the catch ' + error)
})
This is in the then failed

프로미스에서 에러 처리는 가급적 catch 메소드를 이용하시는 것이 좋다.

반례는 아래와 같다.

아래 코드를 보시면 resolve 함수가 정상적으로 호출되고 프로미스가 성공 상태가 되며 then 메소드의 첫 번째 콜백함수가 실행된다.

첫 번째 콜백함수에서 에러가 발생하였고 두 번째 콜백함수가 에러를 잡아내지 못하고 있다.

const promise = () => new Promise((resolve, reject) => {
    let a = 1 + 1

    if(a == 2) {
        resolve('success')
    } else {
        reject('failed')
    }
})

promise().then((message) => {
    console.log('This is in the then ' +  message)
    throw new Error('failed')
}, (error) => {
    console.log('This is in the then ' + error)
})
This is in the then success
(node:52580) UnhandledPromiseRejectionWarning: Error: failed


catch를 사용하는 경우에는 then 메서드의 첫 번째 콜백함수에서 발생하는 에러를 잡아낼 수 있다.

const promise = () => new Promise((resolve, reject) => {
    let a = 1 + 1

    if(a == 2) {
        resolve('success')
    } else {
        reject('failed')
    }
})

promise().then((message) => {
    console.log('This is in the then ' +  message)
    throw new Error('failed')
}).catch((error) => {
    console.log('This is in the catch ' +  error)
})
This is in the then success
This is in the catch Error: failed

6. 체이닝 (Chaining)

then()은 새로운 Promise를 반환하므로 연속 처리가 가능하다. 프로미스는 후속 처리 메소드를 체이닝하여 프로미스를 반환하는 여러개의 비동기 함수들을 연결하여 사용할 수 있​다.

첫번째로 호출한 비동기 함수(promise)의 결과값을 then 후속 처리 메소드를통해 두번째 비동기 함수로 전달하였고 그 결과값을 메세지로 출력하게된다.

const promise = (result) => {
    return new Promise((resolve, reject) => {
        if(result == 'success')
            resolve('success')
        else
            reject('failed')
    })
}

promise('success')
    .then(promise) // .then(result => promise(result))
    .then(message => console.log('This is in the then ' + message))
    .catch(error => console.log('This is in the catch ' + error))
This is in the then success

한 마디로 아래와 같은 흐름이다.

doSomething()
    .then(result => doSomethingElse(result))
    .then(newResult => doThirdThing(newResult))
    .catch(error => console.error(error));

7. static 메서드

프로미스는 5가지 정적 메서드를 제공한다. 정적메서드이기 때문에 객체의 생성없이 사용가능하다.

7.1 Promise.resolve

  • 설명: 인자값을 래핑하여 fulfilled 상태의 Promise를 반환한다.
const promise = Promise.resolve('success');
// new Promise(resolve => resolve('success'))
promise.then(message => console.log('This is in the then ' + message));
// 출력: This is in the then success

7.2 Promise.reject

  • 설명: 인자값을 래핑하여 rejected 상태의 Promise를 반​환한다.
const promise = Promise.reject('failed');
// new Promise((resolve, reject) => reject('failed'))
promise.catch(error => console.log('This is in the catch ' + error));
// 출력: This is in the catch failed

7.3 Promise.all

  • 설명: Promise가 담겨있는 배열이나 이터러블 객체를 인자로 받아 병렬 처리한다.
  • 모든 Promise가 fulfilled 상태가 되면, 결과값을 배열로 담아 반환햔다.
  • 하나라도 rejected 상태이면, 전체가 rejected 상태가 된다.
Promise.all([
    new Promise(resolve => setTimeout(() => resolve(1), 1000)),
    new Promise(resolve => setTimeout(() => resolve(2), 2000)),
    new Promise(resolve => setTimeout(() => resolve(3), 3000))
])
.then(console.log)  // 3초 후 출력: [1, 2, 3]
.catch(console.log)

7.3 Promise.race

  • 설명: Promise 배열 중 가장 먼저 완료된 Promise의 결과값을 반환한다.
  • 다른 Promise의 상태는 결과에 영향을 주지 않는다.
Promise.race([
    new Promise(resolve => setTimeout(() => resolve(1), 1000)),
    new Promise(resolve => setTimeout(() => resolve(2), 2000)),
    new Promise(resolve => setTimeout(() => resolve(3), 3000))
])
.then(console.log) // 1초 후 출력: 1
.catch(console.log)

7.5 Promise.allSetteled

  • 설명: Promise 배열을 병렬로 처리하며, 각 Promise의 상태와 결과값을 객체로 반환한다.
  • Promise 중 하나라도 rejected 상태여도 전체가 종료되지 않고 결과를 모두 보여준다.
Promise.allSettled([
    new Promise(resolve => setTimeout(() => resolve(1), 1000)),
    new Promise((resolve, reject) => setTimeout(() => reject(2), 2000))
])
.then(console.log)
/* 출력:
[
  { status: 'fulfilled', value: 1 },
  { status: 'rejected', reason: 2 }
]
*/
  • 특징:
    • fulfilled 상태 → value 프로퍼티 존재
    • rejected 상태 → reason 프로퍼티 존재

참고 자료