Mysql을 사용하여 DB에서 쿼리를 통해 해당하는 값을 받아 리턴해주는 기능을 개발하던 중,
forEach 함수의 콜백이 비동기 함수일 때 경험한 문제이다.
결과를 예상하여 생각대로 짠 코드 내용대로라면 쿼리 결과 값이 배열에 넣어져 반환되어야 했지만,
해당 함수가 끝나기전에 원하지 않는 값이 리턴 되는 현상이 발생하였다.
try {
const videoList = await axios.get(`${api}key=${apiKey}&pkg=${pkg}&page=${pageNumber}&pagesize=${item}`);
const vidoeList = videoList.data.videoInfoList.videoInfoList
const repo = this.episodeRepository;
if (videoList) {
const episodeList = [];
await (async function () {
vidoeList.forEach(async (key) => {
const episode = await repo.getVideoInfoWithLike(key.access_key, userId);
episodeList.push(episode);
});
})().then(function () {
console.log('원하는결과', episodeList);
});
return episodeList;
}
} catch (err) {
return err;
}
상기의 로직이 문제가 되었던 로직이다.
최종 리턴 값으로 episodeList 라는 배열에 값이 담겨져 와야 했지만,
혹시몰라 즉시 실행 함수를 써가면서까지 비동기 로직을 짜보았지만, 결과는 처음 선언되었던 빈 배열 그대로 리턴되었다.
이런 저런 고민끝에 forEach 는 비동기에 사용할 수 없는지 의문이 들었고, 그냥 제일 기본적인
for 문을 사용해보기로 하고,
하기의 코드로 수정을 하였다.
for (let i = 0; i < vidoeList.length; i++) {
const episode = await repo.getVideoInfoWithLike(list[i].access_key, userId);
episodeList.push(episode);
}
return episodeList;
request를 통해 받아온 배열을 for문을 통해 반복하면서 비동기를 통해 repository에서 쿼리로 받아온 결과를 배열에 push 하고 마지막으로 배열을 리턴하였다.
결과는.. 내가 원하는 배열을 받을 수 있었다!!
코드도 훨씬 간결해졌다.
왜 for문은 정상적으로 비동기 처리가 되는지 궁금하여 구글링을 해보았고, 구글링 결과 배열에 비동기 작업을 실시할 때는 forEach 함수를 잘 사용하지 않는다는 것을 알게되었다.
아무리 async await을 통해 비동기적으로 함수를 실행하려 해봤자,
forEach는 콜백을 그저 실행할 뿐 callback이 끝날때 까지 기다렸다가 다음 callback을 실행하는 것이 아니라는 것을 알게 되었다.
이번 계기로 배열에 비동기 작업을 처리할 때 주의해야 할 중요헌 사실을 알게 되었다.