본문 바로가기

자바스크립트

[자바스크립트] forEach는 프로미스를 기다리지 않는다

728x90

메인 화면
팀 소개 프로젝트

  const docs = await getDocs(
    query(collection(db, "info"), orderBy("date", "desc"))
  );

  docs.forEach(async (v) => {
    const { photo, name, mbti, tmi } = v.data();

    // storage에 저장된 사진 파일 가져오기
    const forestRef = ref(storage, photo);
    const photoPath = await getDownloadURL(forestRef);

    const temp_html = `
        <div class="col card-list">
            <div class="card">
                <img id="${v.id}" src="${photoPath}" class="card-img-top ${v.id}" alt="..." />
                <div class="card-body main-card">
                <div class="card-header">
                    <div class="header-wrapper">
                      <h5 class="card-title ${v.id}">${name}</h5>
                      <p class="card-text ${v.id}">${mbti}</p>
                    </div>
                    <button id="${v.id}" class="card-button">삭제</button>
                </div>
                <div class="card-content">
                  <span class="${v.id}">${tmi}</span>
                </div>
                </div>
            </div>
        </div>`;
    $("#card").append(temp_html);
  });

 

상단의 사진과 같이 서버에서 데이터를 가져와서 DOM을 생성하기 위해 forEach와 async-await을 사용했다. 그러나 의도한 바와 다르게 DOM이 일정한 순서없이 제멋대로 생성되었고, DOM 생성 후 등록한 삭제 및 수정 이벤트가 제대로 작동하지 않는 문제가 발생했다.

 

MDN forEach 설명

 

나는 바로 비동기 처리가 제대로 되지 않아 DOM이 생성되는 순서가 엉망이 되어 발생한 문제라고 생각했고, MDN을 통해 forEach를 자세히 알아봤다. 이에 따르면 forEach는 프로미스를 기다리지 않기 때문에 내가 원했던 바와 같이 날짜 순서대로 데이터를 받아오지 못해 DOM이 순서대로 생성되지 않았던 것이다.

 

  const docs = await getDocs(
    query(collection(db, "info"), orderBy("date", "desc"))
  );

  const data = await Promise.all(
    docs.docs.map(async (v) => {
      const { photo, name, mbti, tmi } = v.data();

      const forestRef = ref(storage, photo);
      const photoPath = await getDownloadURL(forestRef);

      return { id: v.id, photoPath, name, mbti, tmi };
    })
  );

  // 가져온 데이터로 DOM 생성하기
  data.forEach((v) => {
    const { id, photoPath, name, mbti, tmi } = v;

    const temp_html = `
    <div class="col card-list">
        <div class="card">
            <img id="${id}" src="${photoPath}" class="card-img-top ${v.id}" alt="..." />
            <div class="card-body main-card">
            <div class="card-header">
                <div class="header-wrapper">
                  <h5 class="card-title ${id}">${name}</h5>
                  <p class="card-text ${id}">${mbti}</p>
                </div>
                <button id="${id}" class="card-button">삭제</button>
            </div>
            <div class="card-content">
              <span class="${id}">${tmi}</span>
            </div>
            </div>
        </div>
    </div>`;
    $("#card").append(temp_html);
  });

 

그래서 Promise.all을 활용해 비동기 처리를 구현하고 Firsebase의 서버에서 받아오는 데이터를 날짜 순으로 data 배열에 저장하였다. 그리고 DOM을 생성하는 로직은 data 배열의 비동기 처리가 완료된 경우 실행되도록 분리했다. 결과적으로 의도한 바와 같이 DOM이 날짜 순으로 제대로 생성되었고, 삭제 및 수정 이벤트도 정상적으로 실행되었다.

 

 

Array.prototype.forEach() - JavaScript | MDN

Array 인스턴스의 forEach() 메서드는 각 배열 요소에 대해 제공된 함수를 한 번씩 실행합니다.

developer.mozilla.org

 

728x90