자바스크립트(JavaScript) - async / await

JavaScript

Posted by kwon on 2020-08-03

async & await

async, await은 프로미스를 좀 더 깔끔하게 작성할 수 있게 해준다.

async

  • 함수 앞에 async 라는 키워드를 붙여주면 자동으로 함수 내의 코드 블럭이 promise로 변경된다.
  • 즉, resolve를 하지 않고 그냥 return 하더라도 Promise 객체를 리턴하게 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function fetchUser() {
return new Promise((resolve, reject) => {
// do network request in 10 sec...
resolve('kwon');
});
}
// 위의 Promise를 async를 사용하여 변경하면 아래와 같다.
async function fetchUser() {
// do network request in 10 sec...
return 'kwon';
}

const user = fetchUser();
user.then(console.log);

await

  • async 키워드가 붙은 함수 내에서만 사용이 가능하다.
  • 비동기 처리를 수행하는 코드 앞에 await을 붙여 사용하면 된다.
  • 이 때, 비동기 처리 메소드가 꼭 프로미스 객체를 반환해야 await이 의도한 대로 동작한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}

function getApple() {
return delay(2000)
.then(() => 'apple');
}
// 위의 getApple을 await을 사용하면 ****아래와 같이 사용할 수 있다.
async function getApple() {
await delay(2000);
return 'apple';
}
  • 이제 다음의 코드를 보자. promise를 사용하여 getApplegetBanana 를 모두 가져오는 함수이다.
1
2
3
4
5
6
7
8
9
function pickFruits() {
return getApple().then(apple => {
return getBanana().then(banana => `${apple} + ${banana}`);
});
}

pickFruits().then(console.log);
// 출력
// apple + banana
  • 마치 콜백 헬과 비슷한 느낌이 든다.
  • 위의 코드에 async / await 을 적용하여 보자.
1
2
3
4
5
async function pickFruits() {
const apple = await getApple();
const banana = await getBanana();
return `${apple} + ${banana}`;
}
  • 훨씬 깔끔해진 것을 볼 수 있다.
  • async / await 에서 에러처리는 try / catch 문을 사용하면 된다.
1
2
3
4
5
6
7
8
9
10
11
12
// 예외 처리 추가
async function pickFruits() {
let apple;
let banana;
try {
apple = await getApple();
banana = await getBanana();
} catch(error) {
console.log(error);
}
return `${apple} + ${banana}`;
}
  • 여기서 문제가 있다. getApple 에서 2초가 소요되고, getBanana 에서 2초가 소요된다.
  • 즉, 총 4초가 소요되는 것이다. getApplegetBanana 와 같이 서로 연관되어 있지 않아 기다릴 필요가 없는 로직이 순차적으로 수행된다면 비효율적이다.
  • 이 부분을 개선해보자.
1
2
3
4
5
6
7
async function pickFruits() {
const applePromise = getApple();
const bananaPromise = getBanana();
const apple = await applePromise;
const banana = await bananaPromise;
return `${apple} + ${banana}`;
}
  • 위와 같이 각각의 함수에 대한 promise를 생성하면, promise는 생성되는 순간 내부의 코드 블럭이 실행되기 때문에 getApplegetBanana 에 해당하는 promise가 실행되게 된다.
  • 이후에 await 을 통해 동기화 해주게 되면 2초 만에 병렬적으로 실행되는 것을 볼 수 있다.
  • 하지만 코드가 지저분해지는 것이 느껴진다..
  • 이럴 때에 유용한 Promise API 가 있는데, 바로 Promise.all() 이다.
1
2
3
4
5
function pickAllFruits() {
return Promise.all([getApple(), getBanana()])
.then(fruits => fruits.join(' + '));
}
pickAllFruits().then(console.log);
  • Promise.all() 프로미스 배열을 전달하게 되면 모든 프로미스들이 병렬적으로 다 받을 때까지 모아준다.

  • 참고로 Promise.race() 라는 API가 있는데, Promise.race() 는 프로미스 배열에서 가장 먼저 값을 리턴하는 프로미스만 전달해준다.

참조
<https://joshua1988.github.io/web-development/javascript/js-async-await/>
<https://www.youtube.com/watch?v=aoQSOZfz3vQ>