async / await이란?
: promise를 좀 더 간편하고 동기적으로 실행되는 것처럼 보이게 만들어주는 것.
동기식으로 코드를 순서대로 작성하는 것처럼, 간편해진다✨
- syntactic sugar
덧붙여진, 그럴싸해 보이는
async / await은 새로운게 추가된 게 아닌, promise 위에 API를 제공한 것.
=> 이렇게 기존에 존재하는 것 위에, 또는 감싸서 간편하게 쓸 수 있게 제공하는 것이 syntactic sugar!(e.g. class)
1. async
1-1. 비동기처리 안했을 경우
function fetchUser() {
do network request in 10 secs ...
return "ellie";
}
const user = fetchUser();
console.log(user);
1-2. promise로 비동기처리 했을 경우
function fetchUser() {
return new Promise((resolve, reject) => {
resolve("ellie");
});
}
const user = fetchUser();
user.then(console.log);
console.log(user);
promise는?
“내가 언제 데이터를 받아올지는 모르겠지만, 이 Promise라는 object만 가지고있으면,
then이라는 콜백함수만 등록해놓으면, 데이터가 준비되는 대로 너가 준비한 콜백함수를 불러줄게!”
resolve, reject를 호출하지 않고 return하면 Promise가 계속 진행중이라고 남아있음.
=> 그래서 promise안에는 꼭 resolve, reject를 이용해서 완료를 해줘야함!
1-3. promise에 async까지 붙인 경우
async function fetchUser() {
return "ellie";
}
const user = fetchUser();
user.then(console.log);
console.log(user);
async를 함수 앞에 쓰면, 코드블럭이 자동적으로 Promise로 바뀐다!
async는 promise를 감싸고있는, promise를 조금 더 간편하게 쓸 수 있는 키워드
2. 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 "🍌";
}
await은 async가 붙은 함수 안에서만 사용할 수 있다!
함수 delay는, 정해진 ms가 지나면 resolve를 호출하는 promise를 return한다
=> getApple에서는 3초를 전달했으니 3초 뒤에 resolve를 호출!
await을 쓰면, delay 끝날 때까지 기다려준다
동기적인 코드를 짜는 것처럼
getBanana를 async가 아닌 promise만으로 쓴다면? 체이닝을 해야한다.
function getBanana() {
return delay(3000).then(() => "🍌");
}
- 두개의 promise를 한번에 써야한다면?
function pickFruits() {
return getApple().then((apple) => {
return getBanana().then((banana) => `${apple} + ${banana}`);
});
}
pickFruits().then(console.log);
promise도 너무 이렇게 중첩적으로 chaining을 하게되면 콜백지옥과 비슷한 문제가 발생.
async function pickFruits() {
const apple = await getApple();
const banana = await getBanana();
return `${apple} + ${banana}`;
}
pickFruits().then(console.log);
async로 하니까 짱편하다!
async function pickFruits() {
try {
const apple = await getApple();
const banana = await getBanana();
} catch {}
}
return `${apple} + ${banana}`;
pickFruits().then(console.log);
에러처리 또한 이런식으로 try catch로 할 수 있다.
4. async 병렬처리 ⭐️⭐️
사과에 1초, 바나나에 1초… 순차적으로 진행하는건 비효율적!
서로 연관이 되어있지 않기 때문에, 서로 기다릴 필요가 전혀 없다
async function pickFruits() {
const applePromise = getApple();
const bananaPromise = getBanana();
const apple = await applePromise;
const banana = await bananaPromise;
return `${apple} + ${banana}`;
}
pickFruits().then(console.log);
promise는 만드는 순간, 그 안에 들어있는 코드블럭이 실행된다!!!
이렇게 만들자마자 promise를 실행시키고, 각 apple과 banana에는 이미 실행시킨 promise를 넣으면 병렬적으로 일어남!
이젠 1초 걸림
5. useful Promise APIs
5-1. Promise.all
: promise 배열을 전달하게 되면, 모든 promise들이 병렬화됨. 다 받을 때까지 모아준다
⭐️⭐️⭐️ 사과를 가져오는데에 바나나가 필요없고, 바나나를 가져오는데 사과가 필요없는 이러한 병렬적인 구조에서 사용이 가능한 API.
function pickAllFruits() {
return (
Promise.all([getApple(), getBanana()])
// 이 promise배열이 다 받아지면!
.then((fruits) => fruits.join("+"))
// 다 받아진 배열이 다시 전달이 된다
// 그 배열을 구분자로 나눠 string으로 묶어라
);
}
pickAllFruits().then(console.log);
5-2. Promise.race
: promise 배열을 전달하게 되면, 딱 하나만 먼저 수행되는 것이 전달되면 걔를 출력한다
function pickOnlyOne() {
return Promise.race([getApple(), getBanana()]);
}
pickOnlyOne().then(console.log);
6. 숙제!
const userStorage = new UserStorage();
const id = prompt("enter your id");
const password = prompt("enter your password");
userStorage
.loginUser(id, password) //loginUser를 호출헤서 id와 psw를 알려줌
.then((user) => userStorage.getRoles(user)) // 알려주는데 성공하면
.then((user) => alert(`Hello, ${user.name}, you have a ${user.role} role`))
.catch(console.log);
이 부분을 async await을 이용해서 깔끔하게 작성해오기!