Javascript 비동기 promise.all

shleecloud·2021년 9월 4일
0

들어가며

저에게 세션이 끝나고 단 하나만 공부할 수 있다고 한다면 전 비동기를 공부할겁니다. 여러분 비동기 공부하세요. 비동기.. 비동기.. 비동기.. 비동기.. 비동기..

머릿속에 자꾸 남는다. 코드스테이츠 크루분이 하신 말씀이 계속 머릿속에 남는다. 세뇌가 이런걸까? 하루종일 비동기 생각을 했다. 나긋한 말투로 비동기를 읊조리는게 너무 강렬했다. 그래.. 비동기.. 비동기.. 비동기를 하자.. 나는 한다 비동기를..

그 날 분노의 트러블슈팅을 하느라 정작 중요한 개념은 어디론가 날라가고 코드 구조만 하루종일 바꿨던 기억이 난다. 누군가 와서 "비동기가 뭐에요?"라고 물어보면 적당히 설명할수는 있지만 어떤 코드 구조로 비동기가 실행되는지 명쾌하게 설명할 수 없었다. 오늘도 설명을 했는데 공부를 한 지금 돌아보면 알맹이가 빠진 설명이었다. 찝찝함과 세뇌가 나를 확실한 이해로 이끌었다. 이제 알았다. 딱 알았다. 핵심부터 들어간다.

😈 Callback Hell은 비동기가 아니다.

비동기 맞는데 갑자기 뭔소리냐? 예를들어 비동기로 실행한 Promise문을 Chaning 구조로 엮어놨다고 가정하자. 이 코드는 getApple()이 끝나길 기다리고 getBanana()를 기다린다. 이전 작업의 끝까지 결과를 기다리고 다음 작업을 시작한다. 이거 비동기 맞아?

  • Promise는 실행되는 순간 작업을 시작한다.
  • await getApple() 실행하는 순간 끝날 때까지 기다린다. 3초동안 숨 참습니다.
  • Apple 받아오고 await getBanana() 받아오기 다시 3초동안 숨 참습니다.
  • 작업당 3초씩 걸린다면 총 6초가 소요된다.
async function pickFruits() {
  const apple = await getApple();
  const banana = await getBanana();
  return `${apple} + ${banana}`;
}

😇 진짜 비동기

우리 생각속에 비동기는 3초씩 걸리는 작업이 2개가 비동기로 실행된다면 3초면 끝나야 한다. 진짜 비동기로 동작하려면 아래 코드로 해야된다.

  • applePromisebananaPromise가 우선 실행된다. 시~작!
    Promise는 실행되는 순간 작업을 시작한다.
  • await가 3초를 기다리고 apple 변수에 getApple() 결과가 할당된 변수를 할당한다.
  • 앞에서 3초를 이미 기다렸기 때문에 곧바로 getBanana() 결과를 할당한다.
  • 비동기로 3초씩 작업해서 총 3초가 소요된다.
async function pickFruits() {
  const applePromise = getApple();
  const bananaPromise = getBanana();
  const apple = await applePromise;
  const banana = await bananaPromise;
  return `${apple} + ${banana}`;
}

이걸 좀 더 이쁘게 하고싶다? 그렇다면 주인공 promise.all 이 등장한다. 배열 형태로 Promise를 받아서 비동기적으로 실행한다.

function pickAllFruits() {
  return Promise.all([getApple(), getBanana()]).then(
    fruits => fruits.join(' + ')
    // ([apple, banana]) => `${apple} + ${banana}` 구조분해할당
  );
}

🤪 promise.all의 에러처리

promise.all 실행 중 하나라도 에러가 났다? 그러면 가장 빠른 기준으로 작업이 종료된다. 예를들어 getBanana() 작업이 1초만에 실패한다면 뒤에 3초 소요되는 getApple() 작업도 같이 취소된다.

function delay(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function getApple() {
  await delay(3000);
  return 'apple';
}
async function getBanana() {
  await delay(1000);
  // 에러 발생은 throw 
  // return으로 에러를 보낼 경우 에러까지 성공했다고 판단한다.
  throw new Error('i am error');
}

function pickAllFruits() {
  return Promise.all([getApple(), getBanana()]).then(
    ([apple, banana]) => `${apple} + ${banana}`
  );
}
pickAllFruits() //
  .then(console.log)
  .catch(console.log);

// 3초와 1초의 작업임에도 1초만에 promise.all이 끝난다.
// Error: i am error
//    at getBanana (async.js:25)
//    at async Promise.all (:5500/index 1)

에러를 throw가 아닌 return으로 보낼 경우 에러까지 성공했다고 판단하고 apple 작업을 마칠때까지 총 3초가 소요되게 된다.
apple + Error: i am error

참조 URL

https://youtu.be/s1vpVCrT8f4
https://ko.javascript.info/async-await
https://dmitripavlutin.com/promise-all

profile
블로그 옮겼습니다. https://shlee.cloud

0개의 댓글