맨 땅에 프론트엔드 개발자 되기

반복문 이후 비동기 처리 async & await 활용 - 에러 기록 본문

코딩 공부 일지/JavaScript

반복문 이후 비동기 처리 async & await 활용 - 에러 기록

헬로코딩 2022. 2. 28. 19:18
728x90

오늘은 firebase storage를 사용하다가 겪은 에러에 대해 기록해보려고 한다.

참고로, 아래 내용은 리액트의 환경이다.

 

1. 에러 내용

 

내가 구현하려고 했던 것은 firebase storage에 이미지 파일을 업로드 한 이후, 그 이미지 파일 경로를 불러와 화면에 출력하는 것이었다. firebase 공식문서를 통해 아래와 같은 내용을 확인할 수 있었고, listAll을 통해 불러와진 이미지 파일들을 forEach문 반복문을 활용해 useState로 상태 변경을 하고 화면에 출력하려고 했다. 

 

 

나의 코드

listAll(listRef)
    .then((res) => {
      let url = [];
      res.items.forEach((itemRef) => {
        url.push({ name: itemRef._location.path_, fullUrl: res2 })
      });
      setImgUrl(url);
    }).catch((error) => {
      // Uh-oh, an error occurred!
    });

 

내 생각은 forEach로 반복문을 실행하여 배열에 값을 추가하고, 그 결과로 state 값을 변경하는 것이었다.

 

그러나 비동기로 들어오는 자료(외부 데이터)를 반복문을 돌리려니 시간이 소요되었고 (=> 비동기) 그 사이에 이미 setImgUrl(url)이 실행되어 아무것도 없는 빈값이 state 값에 담겨 에러가 발생했다.

 

2. 해결 방법

 

콘솔에 이미지 주소가 잘 들어오는 것을 확인했고, 시간차로 들어온다는 것을 알고 '비동기로 처리해야 하는 구나!' 라는 것은 깨달았다. 그러나 아무리 async와 await을 달아주어도 아무런 변화가 없었다. 

그러다가 오랜 구글링 후 forEach 문에서 비동기 처리가 반영이 안 된다는 것을 알게 되었다. 

 

forEach 는 배열 요소를 순차적으로 돌면서 콜백함수를 실행할 뿐, 한 차례의 콜백함수가 끝날때 까지 기다렸다가 다음 콜백함수를 실행하는 것이 아니다. 즉, forEach가 실행되는 동안 인자로 받은 콜백함수가 비동기이든 아니든 기다리지 않고 순차적으로 루프를 돈다.

 

forEach 문은 비동기이든 아니든 루프를 돌면서 콜백함수를 다 실행시켰으니 결과값이 나오든 말든 그냥 다 실행시켜버리고 함수가 종료되고, 결과값은 비동기이기 때문에 시간이 조금 흐른 뒤에 나온다. 그러나 이미 forEach 문이 종료되었기 때문에 결과값이 나오기도 전에 그 다음 스크립트가 실행이 된 것이다. 

 

  • 비동기로 반복문을 처리하고 싶을 땐 for 문을 사용해야 한다. (forEach X)
  • for 문 중에 forEach와 비슷한 것은 for of 가 있다. (for in 은 객체 내의 탐색)

 

수정 코드

listAll(listRef)
    .then((res) => {
      let url = [];
      const list = async () => {
        for(let itemRef of res.items){
          await getDownloadURL(ref(storage, itemRef._location.path_))
          .then((res2) => {
            url.push({ name: itemRef._location.path_, fullUrl: res2 })
          });
        }
        setImgUrl(url);
      }
      list();
    })
    .catch((error) => {
      // Uh-oh, an error occurred!
    });

 

이렇게 수정했더니 반복문을 돌면서 비동기로 들어오는 이미지 파일의 주소가 들어오고 난 뒤 그 결과로 state 값이 변경되게 되었다. 

 

너무 모르겠어서 진짜 토할 뻔 했는데(리터럴리 토할 뻔 함ㅋㅋ) 다행히 해결... 휴...

728x90