자바스크립트 비동기 작업 Promise

Promise 객체는 비동기 작업의 완료 또는 실패를 처리해줍니다.

이는 비동기 작업이 끝날 때 결과를 처리하여 콜백 지옥을 피하게 해주고 코드의 가독성과 유지보수성을 높여줍니다.

Promise 기본 개념

이 객체는 세 가지 상태를 가집니다:

  • pending: 아직 비동기 작업이 완료되지 않은 상태
  • fulfilled: 비동기 작업이 성공적으로 완료된 상태
  • rejected: 비동기 작업이 실패한 상태

객체가 생성되자마자 비동기 작업을 실행하고, then 또는 catch 메소드를 통해 작업의 성공 실패 결과를 처리할 수 있습니다.

Promise 생성자

객체 생성 시 executor function을 매개변수로 받습니다.

이 함수는 두 개의 인자를 받는데, 하나는 성공 시 호출할 resolve 함수이고, 다른 하나는 실패 시 호출할 reject 함수입니다.

const myPromise = new Promise((resolve, reject) => {
  const isSuccess = true;

  if (isSuccess) {
    resolve("작업 성공!");
  } else {
    reject("작업 실패!");
  }
});
promise 예제

위의 예제 코드를 개발자 도구를 통해 실행해 보면 위와 같은 결과를 얻을 수 있습니다.

then, catch, finally

  • then(): 비동기 작업이 성공했을 때 실행
  • catch(): 비동기 작업이 실패했을 때 실행
  • finally(): 작업의 결과에 상관없이 항상 호출
const myPromise = new Promise((resolve, reject) => {
  const isSuccess = true;

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

myPromise
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error(error);
  })
  .finally(() => {
    console.log("비동기 작업 종료.");
  });
promise then catch finally

예제 1: 비동기 작업 순차 실행

여러 비동기 작업을 순차적으로 실행하고 결과를 처리하고 싶을 때 Promise를 사용할 수 있습니다.

then() 메소드를 체이닝하면 순차적으로 실행시킬 수 있습니다.

function task1() {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log("Task 1 완료");
      resolve("Task 1 성공");
    }, 1000);
  });
}

function task2() {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log("Task 2 완료");
      resolve("Task 2 성공");
    }, 1000);
  });
}

task1()
  .then(result => {
    console.log(result);
    return task2();
  })
  .then(result => {
    console.log(result);
  });
promise chaining

위의 스크립트에서는 task1()을 먼저 실행하고 1초 뒤 console.log() 메소드를 통해 콘솔에 메시지를 찍습니다.

그럼 첫 번째 then()이 실행되어 task1()의 결과를 출력하고 리턴 값으로 다른 Promise인 task2()를 실행합니다.

task2()가 완료되면 두 번째 then()이 실행되고 이로서 비동기 작업이 순차적으로 실행되게 됩니다.

예제 2: 비동기 작업 병렬 실행

Promise.all()을 사용하면 여러 비동기 작업을 병렬로 실행하고, 모든 작업이 완료된 후 결과를 처리할 수 있습니다.

function task1() {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log("Task 1 완료");
      resolve("Task 1 성공");
    }, 1000);
  });
}

function task2() {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log("Task 2 완료");
      resolve("Task 2 성공");
    }, 500);
  });
}

Promise.all([task1(), task2()])
  .then(results => {
    console.log("모든 작업 완료:", results);
  })
  .catch(error => {
    console.log("에러 발생:", error);
  });
비동기 작업 병렬 실행

순차 실행이 아닌 병렬 실행이라 task1()과 task2() 중 빠르게 종료된 작업이 먼저 실행되는 것을 확인할 수 있습니다.

또한 지정한 모든 작업이 끝나야 then() 메소드가 실행되는 것도 알 수 있습니다.

예제 3: 병렬 실행 시 하나라도 실패하면 모두 실패

Promise.all은 배열 내의 어느 하나라도 실패하면 전체가 실패한 것으로 간주합니다.

function task1() {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log("Task 1 완료");
      resolve("Task 1 성공");
    }, 1000);
  });
}

function task2() {
  return new Promise((_, reject) => {
    setTimeout(() => {
      console.log("Task 2 실패");
      reject("Task 2 실패");
    }, 500);
  });
}

Promise.all([task1(), task2()])
  .then(results => {
    console.log("모든 작업 완료:", results);
  })
  .catch(error => {
    console.log("에러 발생:", error);
  });
promise.all 실패

이번 예제에서는 먼저 끝나는 task2()가 실패하여 Promise.all()은 나머지 작업의 종료를 기다리지 않고 바로 catch() 메소드를 호출했습니다.

예제 4: 가장 먼저 완료된 작업만 처리

같은 결과를 원하지만 이를 해결하기 위해 여러가지 방법을 시도해야하는 경우가 있습니다.

이때 Promise.race를 쓸 수 있는데, 이는 여러 비동기 작업 중 가장 먼저 완료된 작업의 결과만 반환합니다.

function task1() {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log("Task 1 완료");
      resolve("Task 1 성공");
    }, 1000);
  });
}

function task2() {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log("Task 2 완료");
      resolve("Task 2 성공");
    }, 500);
  });
}

Promise.race([task1(), task2()])
  .then(result => {
    console.log("가장 먼저 완료된 작업:", result);
  })
  .catch(error => {
    console.log("에러 발생:", error);
  });
가장 먼저 완료된 작업만 처리

Promise 정리

이 객체는 비동기 작업을 효율적으로 처리할 수 있는 강력한 도구입니다.

then, catch, finally와 같은 메소드를 사용하여 비동기 작업의 흐름을 제어할 수 있습니다.

또한 Promise.all, Promise.race 등을 통해 여러 작업을 동시에 처리하거나 가장 먼저 완료된 작업을 다룰 수 있습니다.

관련 글

자바스크립트 튜토리얼