본문 바로가기
JS

중첩된 async await

by kicksky 2021. 3. 8.

문제점: 정신차려보니 끝없이 async await를 쓰고 있다. 중첩된 async await를 어떻게 해결할 것인가.

스택오버플로우에서 유명한 질문을 하나 찾았다.

 

질문: forEach로 async await를 호출해보니 작동은 하지만 왠지 수상쩍어보여 이렇게 써도 되냐고 물어봄

import fs from 'fs-promise'

async function printFiles () {
  const files = await getFilePaths() // Assume this works fine

  files.forEach(async (file) => {
    const contents = await fs.readFile(file, 'utf8')
    console.log(contents)
  })
}

printFiles()

 

답변: 당연 작동은 함. 그치만 printFiles가 비동기 여러개 날려버리고 바로 리턴함.

 

#1 순서대로 비동기 처리 - for ... of ...

async function printFiles () {
  const files = await getFilePaths();

  for (const file of files) {
    const contents = await fs.readFile(file, 'utf8');
    console.log(contents);
  }
}

+ for... of... 를 설명하는 16년 댓글: 바벨은 async/await를 generator 함수로 변환하는데, forEach를 쓰면 각각의 이터레이션이 (각자 독고다이 하는) 개별 generator 함수를 갖게 된다. next( ) 컨텍스트 X. 

 

#1 - 2 reduce

async function printFiles () {
  const files = await getFilePaths();

  await files.reduce(async (promise, file) => {
    // This line will wait for the last async function to finish.
    // The first iteration uses an already resolved Promise
    // so, it will immediately continue.
    await promise;
    const contents = await fs.readFile(file, 'utf8');
    console.log(contents);
  }, Promise.resolve());
}

- map은 순서를 보장하지 않으므로 reduce를 사용

 

#2 동시다발적으로 비동기 처리 - Promise.all( )

async function printFiles () {
  const files = await getFilePaths();

  await Promise.all(files.map(async (file) => {
    const contents = await fs.readFile(file, 'utf8')
    console.log(contents)
  }));
}

- 매개변수로 배열을 받는 Promise.all 안에 배열을 매핑하는 이유가 새 배열을 반환하기 때문이였음 (이제 깨달음...)

- 같은 이유로 forEach는 안됨. 리턴값을 기다리지 않기 때문

 

#+ ES2018

async function printFiles () {
  const files = await getFilePaths()

  for await (const contents of files.map(file => fs.readFile(file, 'utf8'))) {
    console.log(contents)
  }
}

ES2018으로는 이러한 방식도 가능하다고 함

 


stackoverflow.com/questions/37576685/using-async-await-with-a-foreach-loop

www.pluralsight.com/guides/handling-nested-promises-using-asyncawait-in-react

 

 

'JS' 카테고리의 다른 글

Class: constructor에서 async await  (0) 2021.03.08
배열 Array: 루프  (0) 2021.03.08
Fetch API  (0) 2021.03.05
Array-like objects, NodeList, HTMLCollection  (0) 2021.03.04
배열 Array: 아이템 추가 및 삭제, flat( )  (0) 2021.03.03

댓글