배열요소에 비동기 작업을 실행할 때 순차처리와 병렬처리로 나눌 수 있다.
<⭐순차처리>는 배열의 순서대로 비동기 작업을 실행하며 실행순서를 보장하는 경우이다. 시간이 다소 소요되는 작업에 대해서는 끝날 때까지 대기하므로 시간이 소요되는 특징이 있고,
<⭐병렬처리>는 배열요소들이 비동기적으로 실행되는 것인데, 요청에 대한 결과가 재각각일 것이다. 배열의 순서와는 달라지므로 실행순서가 중요치 않을 때 빠른 결과를 얻기 위해 구현된다.
1초뒤 result가 찍히는 상황,
1초 마다 result가 출력되도록 수정하자⚒const waitingFunc = () => new Promise(resolve=>setTimeout(()=>resolve("result"),1000)) . function test(){ Array(10).fill(0).forEach(async() => { const result = await waitingFunc() console.log(result) }) } test() //result(10)
forEach문에서 10번 콜백함수를 콜스택에 넣고 바로 비동기 함수를 실행해야하는 함수를 반환하고 종료된다. (forEach입장에서는 반환한 함수가 비동기인지 아닌지 아무 상관없다.)
반환된 10개의 함수는 비동기 함수여서 1초 뒤에 태스크 큐로 이동하게 되고 콜 스택이 비워지면 이벤트 루프에 의해 10개 모두 'result'를 출력하게 된다.
const waitingFunc = () =>
new Promise(resolve=>setTimeout(()=>resolve("result"),1000))
async function test(){
const arr = Array(10).fill(0)
for(let i=0; i<arr.length; i++){
const result = await waitingFunc()
console.log(result)
}
}
test()
const waitingFunc = () =>
new Promise(resolve=>setTimeout(()=>resolve("result"),1000))
async function test(){
const arr = Array(10).fill(0)
for(let x of arr){
const result = await waitingFunc()
console.log(result)
}
}
test()
위 for문
과 for...of문
은 콜백함수를 return하지 않고
즉시 비동기 함수를 실행하는 단계로 접어들어 순차적으로 태스크 큐로 비동기함수를 이동시키고 순차적으로 콜스택으로 이동되어 실행되므로 원하는 결과를 얻을 수 있다.
const timeArr = [3000, 1000, 2000];
function asyncTimer(time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(`${time/1000}초가 지났습니다.`);
resolve();
}, time);
});
}
async function parallel(array) {
const promises = array.map((time) => asyncTimer(time));
await Promise.all(promises);
console.log("all done :)");
}
parallel(timeArr);
//1초가 지났습니다.
//2초가 지났습니다.
//3초가 지났습니다.
//all done :)
주의할 것은 Promise에서 resolve를 실행해야 Promise가 정상적으로 종료됨을 인식하고 await Promise.all
문을 마칠 수 있으며 다음 콘솔인 all done
을 출력할 수 있게 된다.
또 asyncTimer
를 실행한 결과를 순차적으로 담은 함수를 map
함수로 배열에 담았고 이 배열을 Promise.all
에게 전달한 점! : )
const timeArr = [3000, 1000, 2000];
function asyncTimer(time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(`${time/1000}초가 지났습니다.`);
resolve();
}, time);
});
}
async function parallel(array) {
array.forEach(async(time) => await asyncTimer(time)));
await console.log("all done :)");
}
parallel(timeArr);
//all done :)
//1초가 지났습니다.
//2초가 지났습니다.
//3초가 지났습니다.
역시 forEach의 콜백을 실행하는 것으로 종료되고
그 다음 줄인 all done이 실행되게 된다.
비동기 함수를 이해하는데 있어, 콜스텍/태스크큐/이벤트 루프의 흐름을 잘 이해해야 하는 것 같다. 또 함수를 실행하는 단계에서 실행컨텍스트 생성 여부가 어떤 값을 참조하는지를 결정하기도 한다.
배열요소를 비동기적으로 처리할 경우엔 순차/병렬 처리가 있는데,
순서가 중요하지 않은 경우라면 사용자입장에서 병렬처리를 고려하는 것이 좋다.
반복문에서 비동기함수 실행하기 (1)
도움받은 자료: 배열에-비동기-작업을-실시할-때-알아두면-좋을법한-이야기들