async-await 의 동작 원리 (feat.Generator)
- Generator 함수와 Promise 를 기반으로 구현되어있다.
- 비동기 코드를 동기적으로 보이게만드는 문법적 설탕(Syntactic sugar)
- Generator 함수는 실행을 일시 중지 시키고, 나중에 재개할 수 있는 특별한 함수
구현 개요
- async 함수는 내부적으로 Generator 함수로 변환된다.
- await 표현식은 yield 표현식으로 변환된다.
- 특별한 러너함수가 Generator 를 실행하고, Promise 의 해결을 관리한다.
만약 아래와 같이 async 함수를 작성하면
async function fetchData() {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return data;
}
대략 아래와 같이 변환된다.
function fetchData() {
return new Promise((resolve, reject) => {
function* generator() {
try {
const response = yield fetch('https://api.example.com/data');
const data = yield response.json();
resolve(data);
} catch (error) {
reject(error);
}
}
const gen = generator();
function step(nextFn) {
try {
const result = nextFn();
if (result.done) return;
Promise.resolve(result.value).then(
(val) => step(() => gen.next(val)),
(err) => step(() => gen.throw(err))
);
} catch (e) {
reject(e);
}
}
step(() => gen.next());
});
}
특징
- 자동 Promise 래핑
- 모든 async 함수의 반환값은 자동으로 Promise 로 랩핑된다.
- 에러처리
- try-catch 구문을 사용하여, 동기 및 비동기 에러를 모두 처리할 수 있다.