Javascript Promise의 정의와 필요성

Promise는 비동기적인 코드를 더욱 효율적이고 쉽게 작성할 수 있도록 도와주는 객체입니다. Promise는 비동기 작업이 완료될 때 어떤 값을 반환하거나 어떤 작업을 실행합니다. Promise는 두 가지 상태(State)를 가집니다. 하나는 대기 중(Pending)이고 다른 하나는 이행(Fulfilled) 또는 거부(Rejected)입니다.

Javascript에서는 많은 경우에 비동기적인 작업이 필요합니다. 예를 들어 Ajax 요청, 파일 읽기, 타이머 함수 호출 등이 그렇습니다. 이러한 비동기 작업에서 결과가 나타나기 전까지 대기하는 시간동안 다른 코드를 실행해야 합니다. 그래서 Promise가 필요하게 된 것입니다.

Promise의 기본 문법

Promise를 사용하려면 Promise 객체를 생성해야 합니다. Promise 객체를 생성하면서 콜백 함수를 전달해야 합니다. 이 콜백 함수는 resolve와 reject 매개 변수를 받아야 합니다. resolve 함수는 Promise 객체가 성공적으로 이행될 때 호출되고, reject 함수는 Promise 객체가 거부될 때 호출됩니다.

const myPromise = new Promise((resolve, reject) => {
  // 비동기 작업
  if (/* 작업 성공 */) {
    resolve(/* 결과 값 */);
  } else {
    reject(/* 오류 메시지 */);
  }
});

이렇게 Promise 객체를 생성하면 Promise 객체의 상태(State)는 대기 중(Pending)이 됩니다. Promise 객체가 이행되면 이행 상태(Fulfilled)가 되고, 거부되면 거부 상태(Rejected)가 됩니다.

Promise의 상태(State)와 상태 전이(Transition)

Promise 객체는 세 가지 상태(State) 중 하나를 가집니다.

  • 대기 중(Pending): Promise 객체가 생성된 직후 상태이며, 이행되거나 거부될 때까지 기다리는 상태입니다.
  • 이행(Fulfilled): Promise 객체가 성공적으로 이행된 상태입니다.
  • 거부(Rejected): Promise 객체가 거부된 상태입니다.

Promise 객체의 상태는 상태 전이(Transition)를 통해 변경됩니다.

  • 대기 중(Pending) -> 이행(Fulfilled)
  • 대기 중(Pending) -> 거부(Rejected)

Promise 객체가 이행되면 then 메서드를 사용하여 결과 값을 받을 수 있습니다. 거부되면 catch 메서드를 사용하여 오류 메시지를 받을 수 있습니다.

myPromise.then((result) => {
  // 이행될 때 처리할 코드
}).catch((error) => {
  // 거부될 때 처리할 코드
});

Promise의 장점과 사용 예시

Promise는 비동기 작업을 더욱 효율적이고 쉽게 작성할 수 있도록 도와줍니다. Promise를 사용하면 비동기 작업의 결과 값을 간편하게 처리할 수 있습니다. 이렇게 Promise를 사용하면 콜백 지옥(Callback Hell)을 피할 수 있습니다.

예를 들어, Ajax 요청을 보내고 그 결과 값을 받아와 처리하는 코드를 작성해보겠습니다.

ajax('/data.json', function(data) {
  // 첫 번째 요청 성공
  ajax('/user/' + data.id, function(user) {
    // 두 번째 요청 성공
    ajax('/user/' + data.id + '/profile', function(profile) {
      // 세 번째 요청 성공
      // 결과 값 처리
    });
  });
});

이 코드는 콜백 지옥을 유발합니다. Promise를 사용하면 이를 간편하게 처리할 수 있습니다.

ajax('/data.json')
  .then(function(data) {
    // 첫 번째 요청 성공
    return ajax('/user/' + data.id);
  })
  .then(function(user) {
    // 두 번째 요청 성공
    return ajax('/user/' + user.id + '/profile');
  })
  .then(function(profile) {
    // 세 번째 요청 성공
    // 결과 값 처리
  })
  .catch(function(error) {
    // 오류 처리
  });

이렇게 Promise를 사용하면 코드를 간결하게 작성할 수 있습니다.

Promise Chaining(체이닝)과 예외 처리

Promise는 체이닝(Chaining)을 통해 여러 개의 비동기 작업을 순차적으로 처리할 수 있습니다. 체이닝을 사용하면 코드를 간결하게 작성할 수 있습니다.

myPromise.then(function(result) {
  // 첫 번째 이행 상태
  return anotherPromise(result);
}).then(function(result) {
  // 두 번째 이행 상태
  return yetAnotherPromise(result);
}).then(function(result) {
  // 세 번째 이행 상태
}).catch(function(error) {
  // 오류 처리
});

Promise 체이닝에서 예외가 발생하면 다음 then 메서드로 건너뛰어 오류 처리를 할 수 있습니다.

myPromise.then(function(result) {
  // 첫 번째 이행 상태
  return anotherPromise(result);
}).then(function(result) {
  // 두 번째 이행 상태
  throw new Error('예외 발생');
}).then(function(result) {
  // 실행되지 않음
}).catch(function(error) {
  // 예외 처리
});

Promise.all()과 Promise.race()의 사용 예시

Promise.all() 메서드는 여러 개의 Promise 객체를 동시에 처리할 때 사용합니다. Promise.all() 메서드는 모든 Promise 객체가 이행될 때까지 대기합니다. 그리고 이행된 Promise 객체들의 결과 값을 배열로 반환합니다. 만약 Promise 객체 중 하나라도 거부되면 Promise.all() 메서드는 즉시 거부 상태가 됩니다.

Promise.all([promise1, promise2, promise3])
  .then(function(results) {
    // 모든 Promise 객체가 이행된 경우
  })
  .catch(function(error) {
    // 하나 이상의 Promise 객체가 거부된 경우
  });

Promise.race() 메서드는 여러 개의 Promise 객체 중 가장 먼저 이행된 Promise 객체의 결과 값을 반환합니다. 이 메서드는 하나의 Promise 객체라도 이행되면 즉시 결과 값을 반환합니다.

Promise.race([promise1, promise2, promise3])
  .then(function(result) {
    // 가장 먼저 이행된 Promise 객체의 결과 값
  })
  .catch(function(error) {
    // 하나 이상의 Promise 객체가 거부된 경우
  });

Async/Await과 Promise의 관계

하지만 then을 이용한 체이닝도 여전히 복잡하게 보입니다. 그렇기에 Async/Await가 도입되었습니다. Async/Await는 ES2017부터 도입된 비동기 코드 작성을 위한 새로운 방법입니다. Async 함수는 항상 Promise 객체를 반환합니다. 이 함수에서 await 키워드를 사용하면 Promise 객체가 이행될 때까지 대기합니다.

async function myAsyncFunction() {
  const result1 = await myPromise1();
  const result2 = await myPromise2(result1);
  const result3 = await myPromise3(result2);
  return result3;
}

Async/Await를 사용하면 Promise를 더욱 간편하게 사용할 수 있습니다. 현재 대부분 체이닝이 필요한 다중 프로미스를 부를 경우 Async/Await를 사용하여 거의 C언어 같이 동기적으로 수행할 수 있습니다. 하지만 Async/Await 를 사용해야 할 경우 함수를 async로 선언해 주어야 함을 잊지 마시기 바랍니다.

Promise를 사용하는 주요 라이브러리

Promise는 ES6부터 기본적으로 제공되는 객체입니다. 하지만 Promise를 더욱 쉽게 사용할 수 있도록 Promise를 활용한 다양한 라이브러리들이 개발되어 있습니다. 가장 유명한 라이브러리는 jQuery, AngularJS, React, Vue.js 등이 있습니다.

Promise를 사용할 때 주의할 점

Promise를 사용할 때는 다음과 같은 주의점이 있습니다.

  • Promise는 비동기 작업을 수행하기 때문에 순서를 보장하지 않습니다.
  • Promise 객체가 이행되거나 거부될 때 반드시 then() 메서드나 catch() 메서드를 호출해야 합니다.
  • Promise 객체를 여러 번 호출하면 예상치 못한 결과가 발생할 수 있습니다.
  • Promise.all() 메서드를 사용할 때는 처리 시간이 오래 걸리는 Promise 객체를 사용하지 않는 것이 좋습니다.

결론

JavaScript Promise는 비동기 작업을 효율적이고 간결하게 작성할 수 있도록 도와주는 객체입니다. Promise를 사용하면 콜백 지옥을 피하고 비동기 작업의 결과 값을 간단하게 처리할 수 있습니다. 또한 Promise를 사용하면 체이닝을 통해 여러 개의 비동기 작업을 순차적으로 처리할 수 있습니다.

Promise를 사용할 때는 상태 전이를 주의해야 하며, Promise.all()과 Promise.race() 메서드를 사용하여 여러 개의 Promise 객체를 처리할 수 있습니다. 또한 Async/Await를 사용하면 Promise를 더욱 간편하게 사용할 수 있습니다.

JavaScript Promise는 모던 웹 개발에서 필수적인 기술입니다. Promise를 적극적으로 활용하여 더욱 효율적인 코드 작성에 도움을 받으시길 바랍니다.

FAQs

  1. Promise 객체는 언제 사용하나요?
  • Promise 객체는 비동기 작업을 처리할 때 사용합니다.
  1. Promise 객체를 생성할 때 전달하는 콜백 함수에서 어떤 매개 변수를 사용하나요?
  • 콜백 함수에서는 resolve와 reject 매개 변수를 사용합니다.
  1. Promise 객체는 어떤 세 가지 상태를 가지나요?
  • Promise 객체는 대기 중, 이행, 거부 세 가지 상태를 가집니다.
  1. Promise 체이닝을 사용하면 어떤 장점이 있나요?
  • Promise 체이닝을 사용하면 여러 개의 비동기 작업을 간단하게 순차적으로 처리할 수 있습니다.
  1. Promise.all() 메서드는 어떤 경우에 사용하나요?
  • Promise.all() 메서드는 여러 개의 Promise 객체를 동시에 처리할 때 사용합니다.