JavaScript/JavaScript 문법

[JavaScript]Promise 병렬 처리

DevStory 2022. 5. 13.

JavaScript 특징

Promise 병렬 처리하는 방법을 알아보기 전에 JavaScript의 두 가지 특성부터 알아봅시다.


싱글 스레드(single-thread)

JavaScript는 싱글 스레드(Single-Thread) 방식이므로 명령어 또는 코드가 순차적으로 실행됩니다. 그러므로 동시에 2개 이상의 함수를 실행시킬 수 없습니다.


이벤트 루프(Event Loop)

JavaScript는 싱글 스레드 방식으로 동작하므로 이론적으로 비동기 작업이 불가능합니다. 하지만, 싱글 스레드가 이벤트 루프에 의해 처리되므로 멀티 스레딩(Multi-Thread) 방식으로 동작하는 것처럼 보여줍니다.


Promise

Promise는 비동기 처리에 사용되는 객체입니다. JavaScript 특성인 이벤트 루프의 규범을 따르지 않고 비동기 이벤트로 분류됩니다.

이벤트 루프는 Promise를 발견하면 비동기로 동작하는 기능(메서드, 함수)들이 이벤트 루프에서 분리됩니다. 비동기로 동작하는 기능들은 Promise가 이행(fulfilled)될 때까지 대기열(Queue)에 배치됩니다.

버튼을 클릭하면 onClick() 함수가 호출된다고 가정합시다. onClick() 함수에는 두 개의 비동기 호출이 존재합니다.

onClick = async () => {
  try {
    console.time("ABC");
    const data001 = await new Promise((resolve) =>
      setTimeout(resolve, 3000, "promise001")
    );

    const data002 = await new Promise((resolve) =>
      setTimeout(resolve, 5000, "promise002")
    );
    console.timeEnd("ABC");
  } catch (error) {
    console.error(error);
  }
};

실행 결과

ABC: 8004ms

표준 async/await 구문을 사용하여 두 개의 Promise를 처리하면, 코드가 순차적으로 처리되므로 첫 번째 Promise가 해결될 때까지 두 번째 Promise는 실행되지 않습니다.

첫 번째 Promise는 3초, 두 번째 Promise는 5초 걸릴 것으로 예상됩니다. console.time()을 사용하여 onClick() 함수의 실행시간을 측정하면 대략 8초입니다.


Promise.all()

Promise.all() 메서드는 인수로 해결해야 하는 모든 Promise를 가지며, 단일 Promise를 반환합니다.

onClick = async () => {
  try {
    console.time("ABC");
    const data001 = new Promise((resolve) =>
      setTimeout(resolve, 3000, "promise001")
    );

    const data002 = new Promise((resolve) =>
      setTimeout(resolve, 5000, "promise002")
    );

    const data003 = await Promise.all([data001, data002]);
    console.log(data003);
    console.timeEnd("ABC");
  } catch (error) {
    console.error(error);
  }
};

실행 결과

(2) ["promise001", "promise002"]
ABC: 5004.5ms

첫 번째 Promise와 두 번째 Promise 앞에 await 키워드를 제거 후 Promise가 할당된 객체인 data001과 data002를 Promise.all() 메서드에 배열로 전달합니다.

Promise.all() 함수는 두 개의 비동기 요청이 해결될 때까지 기다립니다. 결과적으로 비동기 처리 시간이 감소되며, 두 개의 Promise가 멀티 스레드 방식으로 처리되는 것처럼 보이게 합니다.

Promise.all() 함수는 전달된 Promise에서 하나라도 실패하면, 즉시 거부(reject)합니다.

onClick = async () => {
  console.time("ABC");
  try {
    const data001 = new Promise((resolve) =>
      setTimeout(resolve, 3000, "promise001")
    );

    const data002 = Promise.reject("promise002 reject");

    const data003 = await Promise.all([data001, data002]);
    console.log(data003);
  } catch (error) {
    console.error(error);
  } finally {
    console.timeEnd("ABC");
  }
};

실행 결과

TypeError: undefined is not a promise
ABC: 3.100000001490116ms

data002가 거부되었으므로 data001을 처리하지 않고 catch문으로 바로 이동합니다.


Promise.allSettled()

Promise.allSettled() 함수는 Promise.all() 함수와 동일한 인수를 가지며, 단일 Promise를 반환합니다.

Promise.allSettled() 함수의 특징은 전달된 Promise에서 거부(reject)되었는지 여부에 관계없이 해결된 Promise를 반환한다는 것입니다.

반환된 Promise는 이행된(fulfilled) 상태와 거부(rejected) 상태를 가집니다.

onClick = async () => {
  console.time("ABC");
  try {
    const data001 = new Promise((resolve) =>
      setTimeout(resolve, 3000, "promise001")
    );

    const data002 = Promise.reject("promise002 reject");

    const data003 = await Promise.allSettled([data001, data002]);
    console.log(data003);
  } catch (error) {
    console.error(error);
  } finally {
    console.timeEnd("ABC");
  }
};

실행 결과


정리

  • Promise.all() 함수와 Promise.allSettled() 함수로 Promise를 병렬 처리할 수 있습니다.
  • 모든 Promise가 정상적으로 이행(fulfilled)되어야 하는 경우 Promise.all() 함수를 호출합니다.
  • Promise 거부와 상관없이 병렬로 처리해야 하는 경우 Promise.allSettled() 함수를 호출합니다.
반응형

댓글