본문 바로가기
Javascript

forEach 반복문(loop)에서 비동기(ajax) 동기적으로 처리

by @hohoya33 2021년 03월 30일

async await을 활용하여 반복문에서 비동기 처리를 위해 비동기 완료될 때까지 기다리고 다음 코드로 실행되는 과정입니다.

const delay = () => {
  const randomDelay = Math.floor(Math.random() * 4) * 100
  return new Promise(resolve => setTimeout(resolve, randomDelay))
}

const list = [1, 2, 3, 4, 5]
list.foreach(async data => {
  await delay().then(() => console.log(data))
})

forEach는 반복문 전체가 종료되는 것에 대한 결과를 기다려주지 않습니다.

callback이 동기적으로 실행되면 좋겠지만 forEach는 각 배열의 요소를 돌면서 그냥 callback을 실행하고 다음 entry로 진입합니다. async/await을 사용하더라도 Array 프로토타입 메소드인 forEach만으로는 동기성 코드를 작성하기 어렵습니다.

 

for…of 를 사용한 반복 처리

callback을 사용하는 forEach 대신 for ... of 문을 사용할 수 있습니다. ES6의 for...of문은 Symbole 타입의 iterator 속성을 이용합니다.

const result = async (list) => {
  for (const data of list) {
    await delay().then(() => console.log(data))
  }
}

const list = [1, 2, 3, 4, 5, 6, 7]
result(list)

예상했던 결과대로 출력되었습니다. 그러나 현재 코드는 비동기 처리를 하나씩 처리하고 있습니다. 때문에 배열의 크기가 클 경우 실행 시간도 길어집니다.

 

Promise.all을 이용한 병렬 처리

async / await을 사용하여 비동기 작업을 배열 로 처리하는 경우 순서가 보장되어야 하는 상황이 아니라면 병렬로 처리해 최적화를 할 수 있습니다.

async function processArray() {
  const promises = [1, 2, 3].map(async num => {
    await delay()
    console.log(num)
  })
  await Promise.all(promises);
  console.log('Done!');
}

위 비동기 처리 방법는 각 비동기 처리의 delay 시점에 따라 순서가 바뀔 수 있습니다. Promise.all을 이용한 병렬 처리의 결과값은 순차적으로 병렬 처리가 되지 않았습니다.

 

개의 댓글