JavaScript Promises로 비동기 작업 처리하기: 초보자 가이드

작성일 :

JavaScript Promises로 비동기 작업 처리하기: 초보자 가이드

JavaScript에서 비동기 작업을 처리하는 것은 필수적인 능력입니다. 어떨 때는 서버에서 데이터를 가져오고, 때로는 긴 연산을 비동기적으로 처리해야 합니다. 비동기 작업을 효과적으로 다루기 위해 등장한 개념이 바로 Promises입니다. 이 가이드에서는 Promises가 무엇인지, 왜 중요한지, 그리고 이를 어떻게 사용할 수 있는지에 대해 자세히 설명하려고 합니다.

Promises란 무엇인가?

Promises는 JavaScript에서 비동기 작업을 처리하기 위한 객체입니다. Promise 객체는 아직 완료되지 않은 작업의 최종 결과값을 나타냅니다. Promises는 주로 다음 세 가지 상태를 가집니다:

  1. Pending (대기): 초기 상태, 아직 비동기 작업이 완료되지 않았습니다.
  2. Fulfilled (이행): 비동기 작업이 성공적으로 완료되었습니다.
  3. Rejected (거부): 비동기 작업이 실패했습니다.

Promises는 한 번 처리되면(이행되거나 거부되면) 그 상태를 유지하며, 이후에는 변경되지 않습니다. 비동기 작업이 완료되면 then 메서드를 사용하여 이행된 결과값에 접근하거나, catch 메서드를 사용하여 거부된 이유를 처리할 수 있습니다.

예제: 간단한 Promise 생성하기

다음은 간단한 Promise 객체를 생성하는 예제입니다. 이 경우, Promise는 2초 후에 이행됩니다.

javascript
const myPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('Promise 이행 완료!');
  }, 2000);
});

myPromise.then(result => {
  console.log(result); // 'Promise 이행 완료!' 출력
}).catch(error => {
  console.error(error);
});

이 예제에서 setTimeout 함수는 2초 후에 resolve 함수를 호출합니다. then 메서드는 Promise가 이행되었을 때 호출되며, 결과값을 인수로 받습니다.

왜 Promises가 중요한가?

Promises는 JavaScript에서 비동기 코드를 처리하는 방법을 개선하는 몇 가지 중요한 이유가 있습니다:

  1. 가독성 향상: Promises는 콜백 헬(callback hell)을 جلوگیری하여 코드의 가독성을 높입니다. 콜백 헬은 중첩된 콜백 함수들로 인해 코드가 복잡해지는 현상을 말합니다.
  2. 에러 처리의 일관성: Promises는 에러 처리를 구조화된 방식으로 처리할 수 있습니다. catch 메서드를 사용하면 항상 동일한 방식으로 에러를 처리할 수 있습니다.
  3. 체이닝: Promises는 thencatch 메서드를 활용한 체이닝이 가능합니다. 여러 비동기 작업을 순차적으로 처리할 때 유용합니다.

예제: 콜백 헬과 Promise 비교

콜백 헬의 예제를 먼저 살펴봅시다.

javascript
asyncFunction1(function(result1) {
  asyncFunction2(result1, function(result2) {
    asyncFunction3(result2, function(result3) {
      console.log('최종 결과:', result3);
    });
  });
});

이제 같은 작업을 Promises를 사용하여 구현해 보겠습니다.

javascript
asyncFunction1()
  .then(result1 => asyncFunction2(result1))
  .then(result2 => asyncFunction3(result2))
  .then(result3 => {
    console.log('최종 결과:', result3);
  })
  .catch(error => {
    console.error('에러 발생:', error);
  });

Promise API

Promises는 내장된 여러 메서드를 통해 강력하고 유연한 비동기 처리가 가능합니다. 그 중 몇 가지 주요 메서드를 살펴보겠습니다.

Promise.all

Promise.all 메서드는 주어진 모든 Promise가 이행될 때까지 기다렸다가, 각각의 결과값을 배열로 반환합니다. 만약 하나라도 거부되면, 즉시 거부된 이유를 반환합니다.

javascript
const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => setTimeout(resolve, 2000, 'foo'));
const promise3 = 42;

Promise.all([promise1, promise2, promise3]).then(values => {
  console.log(values); // [3, 'foo', 42] 출력
}).catch(error => {
  console.error(error);
});

Promise.race

Promise.race 메서드는 가장 먼저 이행되거나 거부된 Promise의 결과값 또는 거부 이유를 반환합니다.

javascript
const promise1 = new Promise((resolve, reject) => setTimeout(resolve, 500, '1번 이행')); 
const promise2 = new Promise((resolve, reject) => setTimeout(resolve, 100, '2번 이행'));

Promise.race([promise1, promise2]).then(value => {
  console.log(value); // '2번 이행' 출력
}).catch(error => {
  console.error(error);
});

Promise.allSettled

Promise.allSettled 메서드는 주어진 모든 Promise가 이행되거나 거부될 때까지 기다립니다. 모든 결과를 객체 배열로 반환하며, 각각은 status 필드와 value 또는 reason 필드를 가집니다.

javascript
const promise1 = Promise.resolve('이행됨');
const promise2 = Promise.reject('거부됨');

Promise.allSettled([promise1, promise2]).then(results => {
  results.forEach((result) => console.log(result.status));
});
// 출력: 'fulfilled', 'rejected'

결론

JavaScript의 Promises는 비동기 작업을 좀 더 직관적이고 관리하기 쉽게 해주는 강력한 도구입니다. Promises를 이해하고 효과적으로 사용하는 것은 현대 JavaScript 개발자의 필수 능력 중 하나입니다. 이 가이드를 통해 Promises의 기본 개념과 사용법을 이해하는 데 도움이 되었기를 바랍니다.