본문 바로가기
JavaScript

[JS] Promise

by goblin- 2024. 9. 8.

Promise는 자바스크립트에서 비동기 작업을 처리하는 데 사용되는 객체로, 비동기 작업의 완료 또는 실패 상태를 나타냅니다. 기본적으로 Promise는 비동기 작업이 성공했는지 실패했는지를 추적하고, 그에 맞는 후속 처리를 관리하는 방식입니다. **콜백 지옥(Callback Hell)**을 피하고, 비동기 흐름을 더욱 읽기 쉽고, 관리하기 쉽게 만들어주는 중요한 도구입니다.

 

1. Promise의 기본 개념

 

Promise는 비동기 작업이 완료되었을 때의 약속을 나타냅니다. Promise는 3가지 상태를 가집니다:

 

Pending (대기): 초기 상태로, 비동기 작업이 아직 완료되지 않은 상태입니다.

Fulfilled (이행됨): 작업이 성공적으로 완료된 상태입니다.

Rejected (거부됨): 작업이 실패한 상태입니다.

 

Promise의 구조

 

Promise는 resolve 또는 reject 함수로 이행되거나 거부되며, 각각 성공 또는 실패 상태를 나타냅니다. Promise는 이를 관리하기 위해 then(), catch(), **finally()**와 같은 메서드를 제공합니다.

let promise = new Promise(function(resolve, reject) {
  // 비동기 작업 수행
  let success = true; // 성공/실패를 나타내는 플래그

  if (success) {
    resolve("작업 성공!");
  } else {
    reject("작업 실패!");
  }
});

then(), catch(), finally()

 

then(onFulfilled): Promise가 **이행(Fulfilled)**되었을 때 실행할 함수를 정의합니다.

catch(onRejected): Promise가 **거부(Rejected)**되었을 때 실행할 함수를 정의합니다.

finally(onFinally): Promise의 성공 여부와 상관없이 항상 실행될 함수를 정의합니다.

 

2. Promise 사용 예시

 

다음은 기본적인 Promise 사용 예시입니다. setTimeout을 비동기 작업으로 가정하고, 2초 후 성공적으로 작업이 완료된 후 resolve가 호출됩니다.

let promise = new Promise(function(resolve, reject) {
  setTimeout(() => {
    resolve("2초 후 작업 성공!");
  }, 2000);
});

promise
  .then((result) => {
    console.log(result);  // "2초 후 작업 성공!"
  })
  .catch((error) => {
    console.error(error);
  })
  .finally(() => {
    console.log("Promise 완료");  // 항상 실행
  });

 

3. Promise의 상태 변화

 

Promise는 다음과 같은 순서로 상태가 변경됩니다:

 

1. Pending: Promise가 처음 생성될 때.

2. Fulfilled: resolve가 호출되면 Promise가 이행됩니다.

3. Rejected: reject가 호출되면 Promise가 거부됩니다.

 

Promise는 한 번 상태가 변경되면 다시 상태가 변하지 않습니다. 즉, 이행되거나 거부되면 해당 상태가 고정됩니다.

let promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("작업 성공");
    reject("작업 실패"); // 이 코드는 실행되지 않음
  }, 1000);
});

promise.then(console.log).catch(console.error);  // "작업 성공" 출력

 

4. Promise의 체이닝 (Chaining)

 

Promise 체이닝은 여러 비동기 작업을 순차적으로 처리해야 할 때 유용합니다. 하나의 Promise가 완료되면 다음 then()에서 다른 Promise를 반환하여, 그 결과를 다시 처리하는 방식입니다.

let promise = new Promise((resolve, reject) => {
  setTimeout(() => resolve(1), 1000);  // 1초 후 resolve(1)
});

promise
  .then((result) => {
    console.log(result);  // 1
    return result * 2;    // 다음 then()에 값 전달
  })
  .then((result) => {
    console.log(result);  // 2
    return result * 2;
  })
  .then((result) => {
    console.log(result);  // 4
  });

 

여기서 중요한 점은 then()새로운 Promise를 반환한다는 것입니다. 이 덕분에 여러 비동기 작업을 순차적으로 처리할 수 있으며, 코드의 흐름을 더 쉽게 이해할 수 있습니다.

 

5. Promise.all()과 Promise.race()

 

자바스크립트에서 여러 Promise를 동시에 처리해야 할 때 유용한 메서드가 **Promise.all()**과 **Promise.race()**입니다.

 

5.1 Promise.all()

 

Promise.all()은 주어진 모든 Promise가 이행될 때까지 기다렸다가 결과를 배열로 반환합니다. 만약 하나의 Promise라도 거부되면, 전체 Promise가 거부됩니다.

let promise1 = new Promise((resolve) => setTimeout(resolve, 1000, "첫 번째"));
let promise2 = new Promise((resolve) => setTimeout(resolve, 2000, "두 번째"));
let promise3 = new Promise((resolve, reject) => setTimeout(reject, 1500, "세 번째 실패"));

Promise.all([promise1, promise2, promise3])
  .then((results) => {
    console.log(results);  // 모든 Promise가 성공했을 때 출력
  })
  .catch((error) => {
    console.error(error);  // 하나라도 실패하면 에러 출력
  });

위 코드에서 promise3가 실패하기 때문에, Promise.all()은 그 즉시 거부됩니다.

 

5.2 Promise.race()

 

Promise.race()는 가장 먼저 완료되는 Promise의 결과를 반환합니다. 즉, 여러 Promise 중 가장 빠른 Promise의 결과를 취합니다.

let promise1 = new Promise((resolve) => setTimeout(resolve, 1000, "첫 번째"));
let promise2 = new Promise((resolve) => setTimeout(resolve, 2000, "두 번째"));
let promise3 = new Promise((resolve, reject) => setTimeout(reject, 500, "세 번째 실패"));

Promise.race([promise1, promise2, promise3])
  .then((result) => {
    console.log(result);  // 가장 먼저 완료된 Promise 출력 (세 번째 실패)
  })
  .catch((error) => {
    console.error(error);  // 에러 발생 시 처리
  });

위 코드에서는 promise3가 500ms 후 거부되기 때문에, Promise.race()는 가장 먼저 완료된(거부된) Promise를 반환합니다.

 

6. async/await와 Promise

 

async/await는 Promise 기반 비동기 작업을 더 직관적이고 동기적인 방식으로 처리할 수 있게 해줍니다. await 키워드는 Promise가 해결될 때까지 기다리는 역할을 하며, 이는 비동기 코드를 동기적 코드처럼 읽기 쉽게 만들어줍니다.

 

6.1 async/await의 기본 사용법

async function fetchData() {
  try {
    let result = await new Promise((resolve, reject) => {
      setTimeout(() => resolve("데이터 가져오기 성공!"), 1000);
    });
    console.log(result);  // "데이터 가져오기 성공!" 출력
  } catch (error) {
    console.error(error);
  }
}

fetchData();

async 함수는 항상 Promise를 반환하며, 함수 내부에서 await 키워드를 사용해 Promise의 결과를 기다릴 수 있습니다.

try/catch 블록을 사용해 비동기 작업 중 발생한 에러를 처리할 수 있습니다.

 

6.2 async/await와 Promise.all()

 

Promise.all()async/await을 함께 사용하면, 여러 비동기 작업을 동시에 처리할 수 있습니다.

async function fetchAllData() {
  let [data1, data2, data3] = await Promise.all([
    new Promise((resolve) => setTimeout(resolve, 1000, "데이터1")),
    new Promise((resolve) => setTimeout(resolve, 2000, "데이터2")),
    new Promise((resolve) => setTimeout(resolve, 1500, "데이터3")),
  ]);
  
  console.log(data1, data2, data3);  // 데이터1 데이터3 데이터2 출력
}

fetchAllData();

 

 

결론

Promise는 자바스크립트에서 비동기 작업을 처리하는 중요한 객체로, 콜백 지옥을 피하고 체이닝을 통해 비동기 작업을 순차적으로 처리할 수 있습니다.

Promise의 상태Pending(대기), Fulfilled(이행), Rejected(거부)로 나뉘며, 각각의 상태에서 후속 처리를 할 수 있는 then, catch, finally 등의 메서드를 제공합니다.

Promise 체이닝은 여러 비동기 작업을 순차적으로 처리해야 할 때 유용하며, then()을 통해 하나의 작업이 완료된 후 다음 작업을 정의할 수 있습니다.

**Promise.all()**은 여러 Promise가 모두 이행될 때까지 기다리며, 성공한 결과를 배열로 반환하는 반면, **Promise.race()**는 가장 먼저 완료되는 Promise의 결과를 반환합니다.

**async/await**는 Promise 기반 비동기 작업을 동기적인 방식으로 처리할 수 있게 해주는 문법으로, 코드의 가독성을 크게 개선하며 try/catch를 통해 에러 처리가 가능합니다.

 

결론적으로 Promise는 자바스크립트의 비동기 작업을 처리하는 강력한 도구로, 다양한 상황에서 유용하게 활용됩니다. 또한, **async/await**을 사용하면 비동기 코드를 더욱 직관적으로 작성할 수 있어 가독성과 유지보수성을 높일 수 있습니다.

'JavaScript' 카테고리의 다른 글

[JS] async/await  (1) 2024.09.20
[JS] 얕은복사, 깊은복사  (2) 2024.09.08
[JS] 자바스크립트의 동작방식(비동기,동기)  (0) 2024.09.08
[JS] Callback  (0) 2024.09.08
[JS] 함수와 클래스(this)  (0) 2024.09.08