async
async/await을 사용하면 Promise에 then 메서드를 chain 형식으로 호출하는 것보다 가독성이 향상된다.
// 함수 앞에 async를 붙이면 항상 Promise를 반환한다.
async function getName() {
return 'Mike';
}
console.log(getName()); // Promise {<fulfilled>: 'Mike'}
// 그래서 함수를 호출하고 then을 사용할 수가 있다.
async function getName() {
return 'Mike';
}
getName().then((name) => {
console.log(name); // "Mike"
});
// 만약에 여기서 반환값(return)이 Promise면 해당 값을 그대로 사용한다.
async function getName() {
return Promise.resolve('Tom');
}
getName().then((name) => {
console.log(name); // "Tom"
});
// 만약 함수 내부에서 예외가 발생하면 rejected 상태의 Promise 반환
// 지금은 then만 있어서 안 나왔다.
async function getName() {
// return Promise.resolve('Tom');
throw new Error('err..');
}
getName().then((name) => {
console.log(name); // Uncaught (in Promise) Error: err..
});
// rejected이기 때문에 catch로 확인할 수 있다.
// 그러면 로그로 찍힌다.
async function getName() {
// return Promise.resolve('Tom');
throw new Error('err..');
}
getName().catch((err) => {
console.log(err); // Error: err..
});
await
// await 키워드는 async 함수 내부에서만 사용할 수 있다.
// 일반 함수에서 사용하면 에러가 발생한다.
// await 키워드 오른쪽에는 Promise가 오고 그 Promise가 처리될 때까지 기다린다.
// 그래서 이 코드는 1초 후에 Mike가 찍힌다.
// result에 getName()에서 resolve된 값을 기다렸다가 넣어주는 것이다.
function getName(name) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(name);
}, 1000);
});
}
async function showName() {
const result = await getName('Mike');
console.log(result);
}
console.log('시작');
showName();
코드 예시
const f1 = () => {
return new Promise((res, rej) => {
setTimeout(() => {
res('1번 주문 완료');
}, 1000);
});
};
const f2 = (message) => {
console.log(message);
return new Promise((res, rej) => {
setTimeout(() => {
res('2번 주문 완료');
}, 3000);
});
};
const f3 = (message) => {
console.log(message);
return new Promise((res, rej) => {
setTimeout(() => {
res('3번 주문 완료');
}, 2000);
});
};
f1()
.then((res) => f2(res))
.then((res) => f3(res))
.then((res) => console.log(res))
.catch(console.log);
// 1번 주문 완료
// 2번 주문 완료
// 3번 주문 완료
위 코드를 async/await으로 바꾸기
// 변수의 데이터들이 기다렸다가 들어가는 게 명확하게 보인다.
// Promise와 then을 쓰는 것보다 가독성이 좋다.
// 대부분의 상황에서는 async, await을 쓰는 게 효과적이다.
const f1 = () => {
return new Promise((res, rej) => {
setTimeout(() => {
res('1번 주문 완료');
}, 1000);
});
};
const f2 = (message) => {
console.log(message);
return new Promise((res, rej) => {
setTimeout(() => {
res('2번 주문 완료');
}, 3000);
});
};
const f3 = (message) => {
console.log(message);
return new Promise((res, rej) => {
setTimeout(() => {
res('3번 주문 완료');
}, 2000);
});
};
console.log('시작');
async function order() {
const result1 = await f1();
const result2 = await f2(result1);
const result3 = await f3(result2);
console.log(result3);
console.log('종료');
}
order();
// 시작
// 1번 주문 완료
// 2번 주문 완료
// 3번 주문 완료
// 종료
// 동일하게 실행된다.
rejected의 경우
// 만약 rejected가 되면 어떻게 될까?
// 에러가 났고 코드가 멈췄다.
const f1 = () => {
return new Promise((res, rej) => {
setTimeout(() => {
res('1번 주문 완료');
}, 1000);
});
};
const f2 = (message) => {
console.log(message);
return new Promise((res, rej) => {
setTimeout(() => {
// res('2번 주문 완료');
rej(new Error('err..'));
}, 3000);
});
};
const f3 = (message) => {
console.log(message);
return new Promise((res, rej) => {
setTimeout(() => {
res('3번 주문 완료');
}, 2000);
});
};
console.log('시작');
async function order() {
const result1 await f1();
const result2 await f2(result1);
const result3 await f3(result2);
console.log(result3);
console.log("종료");
}
order();
// 시작
// 1번 주문 완료
// Uncaught (in promise) Error: err..
// 이럴 때 Promise는 그냥 catch를 써줬지만
// async/await 함수에서는 try, catch문으로 감싸면 된다.
// 이 경우 에러 로그를 찍고 이후 작업이 계속 진행된다.
const f1 = () => {
return new Promise((res, rej) => {
setTimeout(() => {
res('1번 주문 완료');
}, 1000);
});
};
const f2 = (message) => {
console.log(message);
return new Promise((res, rej) => {
setTimeout(() => {
// res('2번 주문 완료');
rej(new Error('err..'));
}, 3000);
});
};
const f3 = (message) => {
console.log(message);
return new Promise((res, rej) => {
setTimeout(() => {
res('3번 주문 완료');
}, 2000);
});
};
console.log('시작');
async function order() {
try {
const result1 = await f1();
const result2 = await f2(result1);
const result3 = await f3(result2);
console.log(result3);
} catch (e) {
console.log(e);
}
console.log('종료');
}
order();
// 시작
// 1번 주문 완료
// Error: err..
// 종료
Promise.all을 사용하는 경우
// 이렇게 await 오른쪽에 Promise가 온다.
// 내부에는 배열로 함수들을 넣어준다.
// 이렇게 async/await 함수 내부에서도 비동기 함수를 병렬로 실행할 수 있다.
const f1 = () => {
return new Promise((res, rej) => {
setTimeout(() => {
res('1번 주문 완료');
}, 1000);
});
};
const f2 = (message) => {
console.log(message);
return new Promise((res, rej) => {
setTimeout(() => {
res('2번 주문 완료');
// rej(new Error('err..'));
}, 3000);
});
};
const f3 = (message) => {
console.log(message);
return new Promise((res, rej) => {
setTimeout(() => {
res('3번 주문 완료');
}, 2000);
});
};
console.log('시작');
async function order() {
try {
const result = await Promise.all([f1(), f2(), f3()]);
console.log(result);
} catch (e) {
console.log(e);
}
console.log('종료');
}
order();
// 시작
// undefined
// undefined
// (3) ['1번 주문 완료', '2번 주문 완료', '3번 주문 완료']
// 종료