async-await
은 그 이름이 시사하듯 비동기 동작(Promise)의 상태가 완료될 때까지 기다린 후, 다음 코드를 순차적으로 읽어 나가며 실행합니다.
async-await
은 태스크의 순서가 보장되어야 할 때는 분명 강력하지만, 각각의 태스크가 서로 연관성이 없는 작업일 때는 앞의 작업이 끝날 때까지 기다릴 필요가 없습니다.
const userList = [
{ name: 'ethan', id: 1 },
{ name: "david", id: 2 },
{ name: 'john', id: 3 }
];
// 1초가 걸리는 쿼리
const getUserById = async (id) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
const [user] = userList.filter(user => user.id === id)
resolve(user)
}, 1000)
})
}
// 2초가 걸리는 쿼리
const getAllUsers = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(userList)
}, 2000)
})
}
const fetchData = async () => {
console.time('소요시간 : ')
const user = await getUserById(2)
const userList = await getAllUsers()
// 불러온 데이터를 출력하기까지 최소 3초가 소요된다.
console.log(user)
console.log(userList)
console.timeEnd('소요시간 : ')
}
fetchData()
바로 이런 상황에서 Promise.all
이 빛을 발할 수 있습니다.
Promise.all
은 여러 비동기 동작(promise)을 하나로 묶어 하나의 Promise처럼 관리할 수 있습니다.
const userList = [
{ name: 'ethan', id: 1 },
{ name: "david", id: 2 },
{ name: 'john', id: 3 }
];
const getUserById = async (id) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
const [user] = userList.filter(user => user.id === id)
resolve(user)
}, 1000)
})
}
const getAllUsers = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(userList)
}, 2000)
})
}
const fetchData = async () => {
console.time('소요시간 :')
// Promise.all() 은 실행할 비동기 태스크들이 담긴 배열을 인자로 받습니다.
const [user, userList] = await Promise.all([getUserById(2), getAllUsers()])
console.log(user)
console.log(userList)
console.timeEnd('소요시간 :')
}
fetchData()
Promise.all
은 여러 비동기 태스크를 동시에(병렬적으로) 실행하고, 가장 마지막 태스크가 완료될 때 완료 상태의 프라미스를 반환합니다.
따라서 위의 예제의 실행시간은 모든 태스크를 더한 1초 + 2초가 아닌, 가장 오래 걸린 태스크의 실행시간인 2초 남짓한 시간만이 소요된 모습입니다.
Promise.all
은 잘 사용하면 비동기 로직의 완료시간을 크게 줄여줄 수 있는 문법이지만, 반드시 짚고 넘어가야 할 점이 하나 있습니다. 바로 Promise.all
내부에서는 태스크들의 순서가 제어되지 않기 때문에, 태스크의 순서가 중요한 경우라면 절대로 Promise.all__
을 통해 관리해서는 안된다는 점입니다.