promise chaining을 더 간결하고 간편하게 만들어주는 async와 await api를 알아보자.
async란?
AsyncFunction 객체를 반환하는 하나의 비동기 함수를 정의한다. 암시적으로 promise를 사용해 결과를 반환하는 것이다.
function fetchUser() {
//do network request in 10 secs...
return "오복";
}
const user = fetchUser();
console.log(user);
이렇게 시간이 걸리는 작업을 하는 경우, js는 원래 동기 언어이기 때문에 저 작업이 끝나는 동안 다른 작업을 수행할 수 없다. 그래서 비동기 처리를 해야 하는데, 이걸 promise로 만든다면
function fetchUser() {
//do network request in 10 secs...
return new Promise((resolve, reject) => {
resolve("오보깅");
});
}
const user = fetchUser();
user.then(console.log);
console.log(user);
이걸 async로 변경하면 어떨까?
async function fetchUser() {
//do network request in 10 secs...
return "오보깅";
}
const user = fetchUser();
user.then(console.log);
console.log(user);
function 앞에 async를 달아주면 자동으로 promise를 만들어준다니! 훨----씬 간결해진 것을 확인할 수 있다.
await란?
promise를 기다리기 위해 사용한다. async function 내에서만 사용이 가능하다.
배가 고프니까 바나나랑 사과를 따와보자.
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function getApple() {
await delay(3000);
return "apple";
}
async function getBanana() {
await dealay(3000);
return "banana";
}
이렇게 3초를 기다리면(await) 바나나와 사과를 획득할 수 있다. 이걸 같이 따오는 함수를 만들어보자.
function pickFruits() {
return getApple().then(apple => {
return getBanana().then(banana => `${apple} + ${banana}`);
});
}
pickFruits().then(console.log);
흡사 콜백 지옥을 연상케 한다... async와 await를 사용해 바꿔보자.
async function pickFruits() {
const apple = await getApple();
const banana = await getBanana();
return `${apple} + ${banana}`;
}
getApple(), getBanana()가 일을 끝낼 때까지 await 하고 둘이 같이 return 해 줘! 확실히 이전의 코드보다 직관적인 걸 확인할 수 있다.
근데 getApple도 getBanana도 3초씩 걸리면 3초 걸려 사과 받고 3초 걸려 바나나 받고... 비효율적이다. 이 두 과정이 연관되어있지 않기 때문에 기다리지 않게끔 바꿔주자.
async function pickFruits() {
const applePromise = getApple();
const bananaPromise = getBanana();
const apple = await getApple();
const banana = await getBanana();
return `${apple} + ${banana}`;
}
3초만에 바나나와 사과를 같이 따올 수 있게 됐다! 그렇지만 이것도 코드가 너무 난잡하지 않나? promise의 다른 api를 활용해보자.
promise에 내장되어 있는 all() api를 사용해보자. all api는 promise 배열을 전달할 경우 모든 promise들이 병렬적으로 다 받을 때까지 모아주는 api다.
function pickAllFruits() {
return Promise.all([getApple(), getBanana()]).then(fruits =>
fruits.join(' + ')
);
}
pickAllFruits().then(console.log);
getApple, getBanana라는 promise를 배열로 묶어서 얘네가 다 받아질 경우 fruits에 모아주는 것이다. 이때 배열을 묶어주는 join을 사용한다.
그 뒤 pickAllFruits이 성공적으로 수행한다면(then) console.log를 수행하게 하는 것이다.
한 가지 기능을 추가해보자. 바나나와 사과 중 먼저 딸 수 있는 선착순 과일 1개를 받아오고 싶다면?
function pickOnlyOne() {
return Promise.race([getApple(), getBanana()])
}
pickOnlyOne().then(console.log);
race는 먼저 처리된 걸 가져오는 api다. 위의 코드는 바나나와 사과에 속도 차이가 없으나 속도 차이가 있는 경우 유용하게 사용이 가능하다.