- async / await를 사용하면 비동기 처리를 동기 처리처럼 구현하기가 쉬워진다.
- async / await는 프로미스를 기반으로 동작한다.
- async / await를 사용하면 프로미스의 then/catch/finally 후속 처리 메서드에 콜백함수를 전달해서 비동기 처리 결과를 동기 처리처럼 프로미스를 사용할 수 있다.
async 함수
- await 함수는 반드시 async 함수 내부에서 사용해야 한다.
- async 함수는 async 키워드를 사용해 정의하며 언제나 프로미스를 반환한다.
- async 함수가 명시적으로 프로미스를 반환하지 않더라도 async 함수는 암묵적으로 반환값을 resolve하는 프로미스를 반환한다.
// async 함수 선언문
async function foo(n) {return n;}
foo(1).then(v => console.log(v));
// async 함수 표현식
const bar = async function (n) {return n;};
bar(2).then(v => console.log(v));
// async 화살표 함수
const baz = async n => n;
baz(3).then(v => console.log(v));
// async 메서드
const obj = {
async foo(n) {return n;}
};
obj.foo(4).then(v => console.log(v));
// async 클래스 메서드
class MyClass {
async bar(n) {return n;}
}
const myClass = new MyClass();
myClass.bar(5).then(v => console.log(v));
await 키워드
- await 키워드는 프로미스가 settled 상태(비동기 처리가 수행된 상태)가 될때까지 대기하다가 settled 상태가 되면
- 프로미스가 resolve한 처리 결과를 반환한다.
- await 키워드는 반드시 프로미스 앞에서 사용해야 한다.
async function foo() {
const a = await new Promise(resolve => setTimeout(() => resolve(1), 3000));
const b = await new Promise(resolve => setTimeout(() => resolve(2), 2000));
const c = await new Promise(resolve => setTimeout(() => resolve(3), 1000));
console.log([a, b, c]);
}
foo();
모든 프로미스에 await 키워드를 사용하는 것은 주의해야 한다.
위의 foo 함수는 종료까지 약 6초가 소요된다.
첫 번째 프로미스는 settled 상태가 될 때까지 3초,
두 번째 프로미스는 settled 상태가 될 때까지 2초,
세 번째 프로미스는 settled 상태가 될 때까지 1초가 걸리기 때문이다.
그런데 앞선 3개의 비동기처리는 서로 연관이 없이 개별적으로 수행되는 처리이다.
따라서 순차적으로 처리될 필요가 없다.
여러개의 프로미스가 모두 처리되길 기다려야하는 상황이라면 promise.all을 쓸 수 있다.
async function foo() {
const res = await Promise.all([
new Promise(resolve => setTimeout(() => resolve(1), 3000)),
new Promise(resolve => setTimeout(() => resolve(2), 2000)),
new Promise(resolve => setTimeout(() => resolve(3), 1000))
])
console.log(res);
}
foo();
아래 함수는 앞선 비동기 처리 결과를 바탕으로 다음 비동기 처리를 수행해야 한다.
이럴 경우 await를 써서 순차적으로 처리해야 한다.
async function bar(n) {
const a = await new Promise(resolve => setTimeout(() => resolve(n), 3000));
const b = await new Promise(resolve => setTimeout(() => resolve(a + 1), 2000));
const c = await new Promise(resolve => setTimeout(() => resolve(b + 1), 1000));
console.log([a, b, c]);
}
bar(1);
에러 처리 (try... catch)
콜백함수를 이용한 비동기 처리의 단점은 에러 처리가 곤란하다는 것이다.
에러는 호출자 방향으로 전파된다. 즉 콜스택의 아래 방향(실행 중인 실행 컨텍스트가 푸시되기 직전에 푸시된 실행 컨텍스트 방향)으로 전파된다.
하지만 비동기 함수의 콜백 함수를 호출한 것은 비동기 함수가 아니기 때문에 try catch문을 사용해 에러를 캐치할 수 없다.
다행이게도 async / await에서 에러처리는 try, catch 문을 사용할 수 있다.
콜백함수를 인수로 전달받는 비동기 함수와는 달리 프로미스를 반환하는 비동기 함수는 명시적으로 호출할 수 있어 호출자가 명확하다.
const fetch = require('node-fetch');
const foo = async () => {
try {
const wrongUrl = 'https://wrong.url';
const response = await fetch(wrongUrl);
const data = await response.json();
console.log(data);
} catch (err) {
console.error(err);
}
};
foo();
'Javascript' 카테고리의 다른 글
(JS) 객체 지향 프로그래밍 : 생성자 함수와 프로토타입 비교 (0) | 2022.06.24 |
---|---|
(JS) 객체지향 프로그래밍 (정의, 프로퍼티와 메서드) (0) | 2022.06.24 |
(JS) 제너레이터의 활용 (0) | 2022.06.13 |
(JS) 제너레이터 (0) | 2022.06.13 |
(JS) 사용자 정의 이터러블 (1) | 2022.06.13 |