async / await는 프로미스를 기반으로 동작한다.
async / await 를 사용하면
프로미스의 then/ catch/ finally 후속 처리 메서드에 콜백 함수를 전달해서 비동기 처리 결과를 후속 처리할 필요 없이
--> 마치 동기 처리처럼 프로미스를 사용할 수 있다!
다시 말해, 프로미스의 후속 처리 메서드 없이
--> 마치 동기 처리처럼 프로미스가 처리 결과를 반환하도록 구현할 수 있다.
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));
클래스의 constructor 메서드는 async 메서드가 될 수 없다.
클래스의 constructor 메서드는 인스턴스를 반환해야 하지만,
--> async 함수는 언제나 프로미스를 반환해야 한다.
await 키워드는 프로미스가 settled상태(비동기 처리가 수행된 상태)가 될 때까지 대기하다가
--> settle 상태가 되면 프로미스가 resolve 한 처리 결과를 반환한다.
await 키워드는 반드시 프로미스 앞에서 사용해야 한다.
await 키워드는 다음 실행을 중지시켰다가
--> 프로미스가 settled 상태가 되면 다시 재개한다.
에러는 호출자 방향으로 전파된다.
즉, 콜 스택의 아래 방향(실행중인 실행 컨텍스트가 푸시되기 직전에 푸시된 실행 컨텍스트 방향)으로 전파된다.
하지만, 비동기 함수의 콜백 함수를 호출한 것은 비동기 함수가 아니기 때문에
--> try, catch문을 사용해 에러를 캐치할 수 없다.
(비동기 함수의 콜백 함수를 호출한 것은 아마도 이벤트 루프..?)
(호출하여 콜스텍에 실행 컨텍스트가 생성된(push) 후 평가와 실행은 아마 자바스크립트 엔진이..?)
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 (e) {
console.error(e); // TypeError: Failed to fetch
}
};
// foo 함수는 프로미스를 반환하는 비동기 함수인
// async 함수로, 호출자가 명확하다!
foo();
위 예제의 foo 함수의 catch문은 HTTP통신에서 발생한 네트워크 에러뿐 아니라
--> try 코드 블록 내의 모든 문에서 발생한 일반적인 에러까지 모두 캐치할 수 있다!
async 함수 내에서 catch 문을 사용해서 에러 처리를 하지 않으면,
async 함수는 발생한 에러를 reject하는 프로미스를 반환한다.
따라서 async 함수를 호출하고 리턴된 프로미스 객체(발생한 에러를 reject하는)에
--> Promise.prototype.catch 후속 처리 메서드를 사용해 에러를 캐치할 수도 있다.