여러 개의 배열에 특정 값을 전부 수정하는 요청을 보내야 할 때, 주로 다음과 같은 형태의 코드를 작성하곤 했다.
const result = arrayData.map(async data => {
await postAPI(data);
}
if (result.status)
{
const newData = await getAPI();
setData(newData);
}
그런데 이런 구조로 요청을 보낸 후 수정된 데이터를 반영하려고 GET 요청을 보내면 대부분 POST 하기 전 시점의 데이터를, 다시 말해 최신 상태의 데이터를 받아오지 못하는 것이었다. 어째서인지 이유를 도통 알 수 없었는데, 그 이유를 이제서야 깨달았다.
map() 메서드는 배열 내의 모든 요소 각각에 대하여 주어진 함수를 호출한 결과를 모아 새로운 배열을 반환한다.
위와 같은 구조를 짤 때 나의 추측으로는 await을 사용했기 때문에 각 요소를 돌 때마다 POST 요청이 끝날 때까지 대기할 것이라고 생각했지만, 그건 반만 맞는 이야기였다.
map을 돌면서 마주치는 await 키워드는 API 호출 할때의 비동기 연산이 끝날 때까지 기다리겠지만, map 함수 자체는 그 어떤 비동기 연산도, 요구도 없었기에 배열의 모든 요소의 명령은 내리지만 코드의 흐름은 다음 코드로 넘어가게 되는 것이다.
await Promise.all(arrayData.map(async data => {
await postAPI(data);
});
const newData = await getAPI();
setData(newData);
async 함수는 비동기 요청을 전제로 하기에 무조건 Promise를 리턴하고, 각 요소들에 async 함수를 작성한 arrayData.map이 최종적으로 리턴하는 것은 Promise들로 된 배열들이다.
이 모든 Promsise 요청들이 끝날 때까지 대기하고 싶다면, map을 통해 리턴되는 Promise 배열에 await Promise.all()를 붙여서 모든 Promise가 끝날때까지 기다려야 하는 것이다.
https://springfall.cc/article/2022-11/easy-promise-async-await