responsePlaylist.data 배열에서 요소를 순서대로 꺼내서 HTTP 요청을 보내기 위해 다음과 같은 코드를 작성하였다.
const getPlaylists = async () => {
try {
const responsePlaylist = await axios.get('/api/playlist', {
headers: {
'X-AUTH-TOKEN': token,
},
});
console.log('responsePlaylist.data', responsePlaylist.data);
// 0: {playlistName: '플레이리스트 A'}
// 1: {playlistName: '플레이리스트 B'}
// 2: {playlistName: '플레이리스트 C'}
// 3: {playlistName: '플레이리스트 D'}
responsePlaylist.data.forEach(async (playlist: Playlist) => {
try {
const responseVideo = await axios.get(
`/api/playlist/${playlist.playlistName}?cursorId=-1&size=5`,
{
headers: {
'X-AUTH-TOKEN': token,
},
}
);
console.log('playlist.playlistName', playlist.playlistName);
console.log('responseVideo.data', responseVideo.data);
const videosInPlaylistData: Record<string, VideoInPlaylist[]> = {
[playlist.playlistName]: responseVideo.data.values,
};
console.log('videosInPlaylistData', videosInPlaylistData);
setVideosInPlaylist((prevVideosInPlaylist) => [
...prevVideosInPlaylist,
videosInPlaylistData,
]);
} catch (error) {
console.error('Error fetching data:', error);
alert('재생목록을 불러오는데 실패했습니다.');
}
});
} catch (error) {
console.error('Error fetching data:', error);
alert('재생목록을 불러오는데 실패했습니다.');
}
};
나는 playlistName: '플레이리스트 A'를 이용한 요청이 제일 먼저 이뤄지는 것을 기대했지만, 순서가 보장되지 않고 랜덤으로 요청이 보내졌다.
여러 비동기 작업을 순서대로 실행하려면 각각의 비동기 호출을 기다리는 방법을 사용해야 한다. 그러나 forEach, map의 콜백함수들은 await 키워드를 사용하더라도 서로의 비동기 작업을 기다려주지 않는다.
따라서 배열을 순회하면서 비동기 동작을 순차적으로 처리하려면 다른 방법을 사용해야 한다. 아래와 같이 for 루프를 사용하면 비동기 작업이 완료될 때마다 다음 작업을 시작하므로 순서대로 작업을 수행할 수 있다.
const getPlaylists = async () => {
try {
const responsePlaylist = await axios.get('/api/playlist', {
headers: {
'X-AUTH-TOKEN': token,
},
});
console.log('responsePlaylist.data', responsePlaylist.data);
// 0: {playlistName: '플레이리스트 A'}
// 1: {playlistName: '플레이리스트 B'}
// 2: {playlistName: '플레이리스트 C'}
// 3: {playlistName: '플레이리스트 D'}
// forEach 대신 for 루프를 사용
for (const playlist of responsePlaylist.data) {
try {
const responseVideo = await axios.get(
`/api/playlist/${playlist.playlistName}?cursorId=-1&size=5`,
{
headers: {
'X-AUTH-TOKEN': token,
},
}
);
console.log('playlist.playlistName', playlist.playlistName);
console.log('responseVideo.data', responseVideo.data);
const videosInPlaylistData: Record<string, VideoInPlaylist[]> = {
[playlist.playlistName]: responseVideo.data.values,
};
console.log('videosInPlaylistData', videosInPlaylistData);
setVideosInPlaylist((prevVideosInPlaylist) => [
...prevVideosInPlaylist,
videosInPlaylistData,
]);
} catch (error) {
console.error('Error fetching data:', error);
alert('재생목록을 불러오는데 실패했습니다.');
}
}
} catch (error) {
console.error('Error fetching data:', error);
alert('재생목록을 불러오는데 실패했습니다.');
}
};
한편 map의 경우, Promise.all과 함께 사용하면 순차적으로 비동기 작업이 처리된 배열을 반환받을 수 있다. map를 async/await과 함께 사용하면 일반 배열이 아닌 Promise 배열을 반환한다는 점을 이용한 것이다.
map의 콜백 함수에 async/await를 사용함으로써 순차적으로 실행은 완료되었지만 결과값을 반환하지는 않는 작업을 수행한다. 그 이후 Promise.all을 통해 모든 비동기 작업이 마무리 된 후 한번에 결과값을 반환받는다. 아래는 그 예제이다.
const asyncFunction = async (item) => {
// 비동기 작업을 수행하고 Promise를 반환하는 함수
// ...
};
const mainFunction = async () => {
const array = [1, 2, 3, 4, 5];
const resultArray = await Promise.all(array.map(async (item) => {
// 각 요소에 대한 비동기 작업을 수행
const result = await asyncFunction(item);
return result;
}));
console.log(resultArray); // 비동기 작업의 결과를 포함한 배열 출력
};
mainFunction();