async와 await는 promise를 조금 더 간결하고 간편하게, 동기적으로 실행되는 것 처럼 보이게 만들어줌
즉, promise 에서 사용하는 then을 무수히 남발할 필요가 없음
새로운 것이 추가된 것이 아닌, 기존에 존재하던 promise위에 조금 더 간편한 API를 제공하는 것
Class와 같이 ‘syntactic sugar’로 볼 수 있음
비동기처리를 안했을 경우
//다음과 같이 비동기적인 처리를 전혀 하지 않은 경우, 자바스크립트는 fetchUser()를 실행하면서 10초동안 서버에서 데이터를 받아와서 리턴할때까지 기다린 후에 다음 라인으로 넘어간다.
function fetchUser(){
// do network request in 10 secs....
return 'Dylan';
}
const user = fetchUser();
console.log(user);
Promise 를 이용한 비동기 처리
// 언제 데이터를 서버로부터 user의 데이터를 받아올진 모르겠지만, Promise라는 오브젝트를 정의해두고, 여기에 then이라는 콜백함수만 등록해놓으면 유저의 데이터가 준비되는대로 불러주겠다고 약속하는것
function fetchUser() {
return new Promise((resolve, reject) => {
//do network in 10 secs
resolve("dylan");
});
}
const user = fetchUser();
user.then(console.log); // 10초후 dylan 출력
async를 이용한 비동기처리
// 1. async
// async를 사용하면 번거롭게 Promise를 쓰지않아도 자동적으로 함수안에 있는 코드블록들이 Promise로 변환됨
// syntactic sugar
async function fetchUser() {
//do network request in 10 secs...
return 'dylan';
}
const user = fetchUser();
user.then(console.log);
await
function delay(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
async function getApple() {
await delay(3000);
return "🍎";
}
async function getBanana() {
await delay(3000);
return "🍌";
}
function pickFruits() {
return getApple().then((apple) => {
return getBanana().then((banana) => `${apple} + ${banana}`);
});
}
pickFruits().then(console.log); // 🍎 + 🍌
위의 코드와 같이 Promise도 중첩적으로 체이닝을 하면 콜백지옥과 비슷한 문제점(가독성 등)이 발생한다..
그래서 await을 이용
function delay(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
async function getApple() {
await delay(1000);
return "🍎";
}
async function getBanana() {
await delay(1000);
return "🍌";
}
async function pickFruits() {
const apple = await getApple();
const banana = await getBanana();
return `${apple} + ${banana}`;
}
pickFruits().then(console.log);
에러 핸들링
function delay(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
async function getApple() {
await delay(1000);
throw 'get apple error';
return "🍎";
}
async function getBanana() {
await delay(1000);
throw 'getbanana error'
return "🍌";
}
async function pickFruits() {
try {
const apple = await getApple();
const banana = await getBanana();
} catch(){
console.log(error);
}
return `${apple} + ${banana}`;
}
pickFruits().then(console.log);
위의 코드를 보면 getApple()에서 1초, getBanana() 에서 1초가 소요된다.
저 두 함수 간에는 연관이 없으므로 조금더 효율적으로 만들수 있다.
서로 연관이 없으므로 병렬으로 처리하는 것이 좋다
function delay(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
async function getApple() {
await delay(1000);
throw 'error';
return "🍎";
}
async function getBanana() {
await delay(1000);
return "🍌";
}
async function pickFruits() {
const applePromise = getApple(); // 만들자마자 getApple()코드 실행
const bananaPromise = getBanana(); // 만들자마자 getBanana()코드 실행
const apple = await applePromise; // await로 기다림 (동기화)
const banana = await bananaPromise; //
return `${apple} + ${banana}`; // 1초만에 완료
}
pickFruits().then(console.log);
하지만 위의 방법보다 더 쉽게 만들수 있는 API를 제공한다
useful APIs
function delay(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
async function getApple() {
await delay(1000);
throw "error";
return "🍎";
}
async function getBanana() {
await delay(1000);
return "🍌";
}
// async function pickFruits() {
// const applePromise = getApple(); // 만들자마자 getApple()코드 실행
// const bananaPromise = getBanana(); // 만들자마자 getBanana()코드 실행
// const apple = await applePromise; // then 대신 await로 기다림 (동기화)
// const banana = await bananaPromise;
// return `${apple} + ${banana}`;
// }
pickFruits().then(console.log);
// 3. useful Promise APIs
// Promise.all([]) : 프로미스 배열을 전달하게 되면 모든 프로미스들이 병렬적으로 다 리턴 받아질때까지 모아줌
function pickAllFruits() {
return Promise.all([getApple(), getBanana()]).then((fruits) =>
fruits.join("+")
);
}
pickAllFruits().then(console.log); // 🍎 + 🍌
function delay(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
async function getApple() {
await delay(1000);
throw "error";
return "🍎";
}
async function getBanana() {
await delay(1000);
return "🍌";
}
// Promise.race([]);
// 어떤것이든 상관없고 먼저 리턴되는 하나만 받아오고 싶을때
function pickOnlyOne(){
return Promise.race([getApple(),getBanana()]); // Promise.race는 먼저 수행되는 애만 리턴
}
pickOnlyOne().then(console.log); // 🍌
이전 유저 로그인 예제 변환(promise -> async & await)
class UserStorage {
loginUser(id, password) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (
(id === "dylan" && password === "test") ||
(id === "coder" && password === "test")
) {
resolve(id);
} else {
reject(new Error("not found"));
}
}, 2000);
});
}
getRoles(user) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (user === "dylan") {
resolve({ name: "dylan", role: "admin" });
} else {
reject(new Error("no access"));
}
}, 1000);
});
}
}
let id = prompt('input your id ');
let passwd = prompt('input your password');
const userStorage = new UserStorage();
async function getUserWithRole(id,passwd) {
const login = await userStorage.loginUser(id, passwd);
const role = await userStorage.getRoles(id);
return alert(`Hello ${login}, you have a ${role.role} role`);
}
getUserWithRole(id,passwd)
.then(console.log)
.catch(console.log);
Mingsayz
- Software Engineer
- E-commerce PM / PO
1994.12.02
Working in Vietnam 🇻🇳