반복문 내에서 일어나는 모든 비동기 구문을 기다려주는 구문이다.
예를 들어 반복해서 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 통신 완료
타이머 예시를 통해 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 | |
---|---|---|---|
다수의 비동기 작업이 한 번에 실행되는가? | o | o | x |
다수의 비동기 작업이 모두 끝나기를 기다리는가? | x | o | o |
👍