ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java Script] for과 forEach의 차이 및 배열의 비동기 작업
    Java Script 2023. 8. 28. 14:49

     

    자바스크립트로 프로젝트를 하다가 외부에서 배열 데이터를 가져와서 

    출력하는 코드를 작성한 적이 있는데 화면에 출력될 때 순서가 보장되지 않는 문제가 발생하였습니다.

    발생한 문제의 예시를 한번 들어보겠습니다.

     

    예시로 사용하기 위해 무료 open API로 숫자에 대한 흥미로운 지식을 알려주는 Numbers API라는 걸 사용해 보겠습니다.

    http://numbersapi.com/

     

    Numbers API

    NumbersAPI An API for interesting facts about numbers Bring meaning to your metrics and stories to your dates An API for interesting facts about numbers Bring your metrics and dates to life Let your metrics tell tales with our API of number facts What tale

    numbersapi.com

    우선 이런 식으로 숫자가 인수로 주어지면 해당 숫자의 데이터를 리턴해주는 함수를 만들고

    const getData = async (i) => {
      try {
        const res = await fetch(`http://numbersapi.com/${i}`);
        const data = await res.text();
        return data;
      } catch (err) {
        console.log(err);
      }
    };

    1부터 4까지의 데이터를 출력하기 위해 [1, 2, 3, 4]라는 배열을 만들고 

    forEach로 그 배열을 순회하면서 데이터를 출력하도록 만들었습니다.

    async function fun() {
      const arr = Array.from({ length: 4 }, (v, i) => i + 1);
      arr.forEach(async (v) => {
        const item = await getData(v);
        console.log(item);
      });
    }
    
    fun();

    저는 여기서 당연히 [1, 2, 3, 4]의 데이터가 순서대로 들어가면서 화면에 출력될 때도 순서대로 출력될 줄 알았는데

    아래처럼 계속 순서가 바뀌면서 출력되는 현상을 격었습니다.

    그래서 찾아봤는데 forEach는 for과는 다르게 배열을 돌면서 forEach의 콜백함수를 실행하고

    다음 항목으로 이동할 때 콜백함수가 완료되길 기다리지 않고 다음으로 넘어간다고 합니다.

     

    쉽게 말해 forEach는 콜백함수를 호출하기만 할 뿐 내부에 비동기 처리에 관해서는 관심이 없다는 것이었습니다.

    이러한 이유 때문에 순서가 보장이 안 되는 거였습니다.

     

    그럼 순서를 보장하려면 어떻게 해야 할까?

    생각해 보면 답은 간단했습니다.

     

    비동기 처리를 순서가 보장돼도록 순차처리를 하고 싶으면 for문이나 for of 문을 사용하면 됩니다.

    아래 코드처럼 for of를 이용하여 배열의 비동기 작업을 순차로 처리하면

    async function fun() {
      const arr = Array.from({ length: 4 }, (v, i) => i + 1);
      for (let x of arr) {
        const item = await getData(x);
        console.log(item);
      }
    }
    fun();

    이런 식으로 화면에 순서가 보장되어 순차적으로 출력이 됩니다.

    하지만 이런 식으로 하면 비동기 작업을 순차적으로 처리하다 보니 데이터를 가져오는 시간이 길어질 수밖에 없습니다.

     

    배열의 비동기 작업을 병렬적으로 처리하면서 순서가 보장되도록 하고 싶은데

    다행히 방법이 있었습니다. 바로 Promise.all()을 사용하면 된다는 것이었습니다.

    Promise.all() 함수는 쉽게 말하면 동시에 여러 개의 비동기 작업을 처리하고, 모든 작업이 완료되면 한 번에 결과 값을 배열로 주는 함수라고 합니다.

     

    그럼 Promise.all()을 사용하여 비동기 작업을 병렬처리 하려면 아래 처럼 하면 됩니다.

    async function fun() {
      const arr = Array.from({ length: 4 }, (v, i) => i + 1);
    
      const map = arr.map(async (v) => await getData(v)); // 반환 되는 Promise들을 배열로
      const items = await Promise.all(map); // 각 Promise들의 resolve를 기다린 후 그 결과를 담은 배열 생성
    
      items.forEach(async (item) => {
        console.log(item);
      });
    }
    
    fun();

    이런 식으로 하면 배열의 비동기 작업의 병렬 처리가 가능해저서 데이터를 더 빨리 가져올 수 있습니다.

Designed by Tistory.