for await of 문의 이해

hiro2474·2020년 3월 29일
9
post-thumbnail

for await of 구문은 무엇을 위한 것인가?

반복문 내에서 일어나는 모든 비동기 구문을 기다려주는 구문이다.

예를 들어 반복해서 api 통신을 하는 코드가 있다고 하자.

const names = ['a', 'b', 'c', 'd'];

names.forEach(async (name) => {
  const result = await fetch(`https://someurl.com/names/${name}`);
  console.log(result.json());
});

console.log('모든 api 통신 완료'); // 이 부분이 forEach의 반복문 작업이 모두 끝나기 전에 실행된다.

위의 코드를 실행하면 다음과 같은 결과가 나온다.

$ 모든 api 통신 완료
$ <json result 'a'...>
$ <json result 'b'...>
$ <json result 'c'...>
$ <json result 'd'...>

중요한 포인트는 forEach에서의 모든 비동기 작업이 끝나는 것을 기다리지 않는다는 것이다.
이 문제를 다음과 같이 for await 문을 사용해서 해결할 수 있다.

const names = ['a', 'b', 'c', 'd'];

for await (let name of names) {
  const result = await fetch(`https://someurl.com/names/${name}`);
  console.log(result.json());
}

console.log('모든 api 통신 완료'); // forEach의 반복문이 끝나기를 기다린 후 로깅을 한다.

실행해보면 결과는 다음과 같다.

$ <json result 'a'...>
$ <json result 'b'...>
$ <json result 'c'...>
$ <json result 'd'...>
$ 모든 api 통신 완료

Promise.all()과의 차이는 뭐지?

  • promise.all()은 인자의 프로미스 배열을 동시에 실행한다.
  • for await of 내의 비동기 작업은 루프를 돌며 순차적으로 실행된다.

타이머 예시를 통해 for await of문과 Promise.all()의 차이를 알아보자. 추가로 forEach 메소드 안에서 async function을 사용한 결과와도 비교해보자.

<타이머 함수 정의>

const timer = (time) => {
  return new Promise((resolve, reject) => {
    console.log(`${time} 타이머 시작`);
    setTimeout(() => {
      console.log(`${time} 타이머 끝`);
      resolve();
    }, time);
  });
};

<Promise.all()을 이용한 여러 타이머 실행>

async function runPromiseAll() {
  const times = [3000, 1000, 7000, 5000];

  await Promise.all(times.map((time) => timer(time)));

  console.log('모든 타이머 끝');
}
$ 3000 타이머 시작
$ 1000 타이머 시작
$ 7000 타이머 시작
$ 5000 타이머 시작
$ 1000 타이머 끝
$ 3000 타이머 끝
$ 5000 타이머 끝
$ 7000 타이머 끝
$ 모든 타이머 끝

<for await of문을 이용한 여러 타이머 실행>

async function runForAwait() {
  const times = [3000, 1000, 7000, 5000];

  for await (let time of times) {
	  await timer(time);
  }

  console.log('모든 타이머 끝');
}
$ 3000 타이머 시작
$ 3000 타이머 끝
$ 1000 타이머 시작
$ 1000 타이머 끝
$ 7000 타이머 시작
$ 7000 타이머 끝
$ 5000 타이머 시작
$ 5000 타이머 끝
$ 모든 타이머 끝

<forEach 메소드 안에 async function을 사용하여 여러 타이머 실행>

async function runForEach() {
  const times = [3000, 1000, 7000, 5000];

  times.forEach(async (time) => {
    await timer(time);
  })

  console.log('모든 타이머 끝');
}
$ 3000 타이머 시작
$ 1000 타이머 시작
$ 7000 타이머 시작
$ 5000 타이머 시작
$ 모든 타이머 끝
$ 1000 타이머 끝
$ 3000 타이머 끝
$ 5000 타이머 끝
$ 7000 타이머 끝

직접 실행해보며 왜 이런 결과가 나왔는지 고민해보시길 바란다.

정리

forEach(async () => {})await Promise.all()for await ... of
다수의 비동기 작업이 한 번에 실행되는가?oox
다수의 비동기 작업이 모두 끝나기를 기다리는가?xoo
profile
행복한 인생의 성장을 추구합니다.

2개의 댓글

comment-user-thumbnail
2020년 9월 17일

👍

답글 달기
comment-user-thumbnail
2020년 9월 18일

잘봤습니다~!

답글 달기