본문 바로가기

javascript

[javascript] for와 forEach의 차이, forEach에서 비동기 처리 하는 방법

자바스크립트를 처음 공부하다 보면 이런 난관에 빠지게 된다.

 

아래 코드는 비동기함수를 이용해서 arr 배열에 값을 넣는 코드이다.

비동기 함수를 사용하고 있기에 async, await를 사용해서 제대로 arr 배열에 값이 들어가도록 하고 있다.

const a = new Array(10).fill(1)
const arr = []
const asyncFunction = (i) => {
  return new Promise(resolve => {
    setTimeout(() => {
      arr.push(i)
      resolve()
    }, 100);
  })
}

(async() => {
  for (let i = 0; i < a.length; i++) {
    await asyncFunction(i)
  }
  console.log(arr)
})()

이 코드를 실행하면 예상대로 arr 값에 정상적으로 값이 들어가는 것을 알 수 있다.

 

 


 

그러면 아래 코드는 어떨까?

for문은 아름답지 않기에 for 대신 forEach를 사용해서 값을 넣어보도록 하자

 

const a = new Array(10).fill(1);
const arr = []
const asyncFunction = (i) => {
  return new Promise(resolve => {
    setTimeout(() => {
      arr.push(i)
      resolve()
    }, 1000);
  })
}

a.forEach(async (_, i) => {
  await asyncFunction(i)
})

console.log(arr)

 

결과 값은 어떨까?

당연히 바뀐건 forEach로 바뀐 것밖에 없으니 정상적으로 나올 것처럼 보인다.

 

그러나 결과값을 보면 빈 배열 값이 나오는 것을 볼 수 있는데 이유가 뭘까?

 

arr를 살펴봐도 아무 값이 없다.

 

이렇게 되는 이유는 forEach가 await를 기다려주지 않기 때문이다.

요즘 리액트나 뷰 같은 SPA에서 자주 쓰는 axios도 비동기가 기본인데 이렇게 되면 forEach에서 axios를 쉽게 쓸 수 없는 것.

 

이 현상은 forEach뿐 아니라 reduce, map, filter 등의 Array prototype 메서드에서 나타난다.

 

좌측부터 map, reduce, filter

 


 

그러면 어떻게 해야할까?

비동기 함수를 쓰려면 옛날 방식인 for문을 사용해야 할까?

 

일단 for문 대신 사용할 수 있는 방법은 for ... of 가 있다.

const a = new Array(10).fill(1)
const arr = []
const asyncFunction = (i) => {
  return new Promise(resolve => {
    setTimeout(() => {
      arr.push(i)
      resolve()
    }, 100);
  })
}

(async() => {
  for (let i = 0; i < a.length; i++) {
    await asyncFunction(i)
  }
  console.log(arr)
})()

 

정상적으로 나온다.

 

다른 방법으로는 map과 Promise.all을 사용하는 방법이 있다.

 

const a = new Array(10).fill(1);
const arr = []
const asyncFunction = (i) => {
  return new Promise(resolve => {
    setTimeout(() => {
      arr.push(i)
      resolve()
    }, 1000);
  })
}

const promise = a.map(async (_, i) => {
  await asyncFunction(i)
})

Promise.all(promise)
  .then(() => console.log(arr))

 

 

forEach 사용하면서 당황하는 일이 없도록 하자