반복문에서 비동기 함수 실행하기(2)_배열

junamee·2021년 10월 4일
1

자바스크립트

목록 보기
9/11

배열에 비동기 함수 실행하기

배열요소에 비동기 작업을 실행할 때 순차처리와 병렬처리로 나눌 수 있다.
<⭐순차처리>는 배열의 순서대로 비동기 작업을 실행하며 실행순서를 보장하는 경우이다. 시간이 다소 소요되는 작업에 대해서는 끝날 때까지 대기하므로 시간이 소요되는 특징이 있고,
<⭐병렬처리>는 배열요소들이 비동기적으로 실행되는 것인데, 요청에 대한 결과가 재각각일 것이다. 배열의 순서와는 달라지므로 실행순서가 중요치 않을 때 빠른 결과를 얻기 위해 구현된다.

순차처리

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'를 출력하게 된다.

01. for문 변경

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()

02. for .. of 반복

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하지 않고
즉시 비동기 함수를 실행하는 단계로 접어들어 순차적으로 태스크 큐로 비동기함수를 이동시키고 순차적으로 콜스택으로 이동되어 실행되므로 원하는 결과를 얻을 수 있다.

병렬처리

01. 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) {
  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에게 전달한 점! : )

* forEach를 사용하면 ?

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)
도움받은 자료: 배열에-비동기-작업을-실시할-때-알아두면-좋을법한-이야기들

profile
아티클리스트 - bit.ly/3wjIlZJ

0개의 댓글