지난 포스트에서 다룬 Promise 객체는 기존의 콜백 지옥을 크게 개선시켜준 문법입니다. 하지만 이 역시도 비동기 처리가 늘어날수록 then, catch 메소드가 꼬리를 이어 코드가 복잡해집니다. 그래서 ES8에서는 async
와 await
라는 문법을 도입해서 프로미스 객체들을 더욱 간결하게 만들어주었습니다.
async
와 await
는 다음과 같이 사용합니다. async
는 비동기 처리 함수 앞에, await
는 프로미스 객체의 앞에 키워드를 사용합니다.
async function 함수명(){
}
await 프로미스;
구체적인 예시는 대표적 비동기 처리 함수인 setTimeout() 메소드를 가지고 알아보겠습니다.
setTimeout 메소드는 특정 시간이 지난 후 코드를 실행합니다. 즉, setTimeout이 호출되면 카운트를 실행하고 일정 시간 후에 메소드 내부의 코드를 실행하는데, 이 카운트를 세는동안 브라우저는 계속해서 스크립트를 읽어나갑니다. 따라서 setTimeout은 비동기 처리 함수의 가장 대표적인 예시라고 볼 수 있습니다.
Promise 객체
를 이용한 비동기 처리 코드를 보겠습니다. setTimeout을 사용해서, 함수가 호출되고 1초 후에 문자열을 출력하는 코드입니다.
function func() {
console.log('func() 실행 중');
return new Promise((resolve => {
setTimeout(resolve('promise'), 1000);
}));
}
func().then((message)=> {
console.log(message);
})
.catch((errorMessgae)=>{
console.log(errorMessgae);
});
물론 간단한 코드라서 프로미스 객체를 사용해도 그렇게 복잡하다고 느끼지 못 할 수도 있습니다. 그러면 위 코드를 async
를 사용해서 바꿔보겠습니다.
async function func() {
console.log('func() 실행 중');
return 'promise with async';
}
func().then((message)=> {
console.log(message);
})
.catch((errorMessgae)=>{
console.log(errorMessgae);
});
프로미스를 return 하는 구문이 굉장히 간단해지지 않았나요? 위처럼 함수 앞에 async
키워드를 붙이면 결과로는 항상 프로미스 객체를 반환합니다. 만약 async
키워드가 없다면, 문자열을 반환했다고 했을 것 입니다. async
가 붙은 함수는 자동적으로 resolve가 된 프로미스 객체를 반환합니다.
이번에는 await
도 사용해보겠습니다. await
는 async
키워드가 붙은 함수 내부에서만 사용가능한 키워드입니다. await
는 비동기 처리 함수 내부에서 지정한 프로미스 객체가 resolve 될 때 까지 기다리는 기능을 합니다. 역시, 방금전에 사용했던 코드에 await
구문을 추가해보겠습니다.
console.log('func() 시작');
func();
console.log('func() 종료');
async function func() {
console.log('func() 실행 중');
const promise = new Promise((resolve, reject) => {
setTimeout(()=>{
resolve('await', 1000);
});
});
console.log(await promise);
}
일반적으로 생각했을 때, 시작 -> 실행 중 -> await -> 종료의 순서대로 반환할 것 같지만 아닙니다. 순서대로 실행은 하되, 비동기 처리 함수를 부르고나서 실행 완료까지 기다리지 않고 계속 스크립트를 해석합니다. 그리고 await
가 완료되면 그제서야 해당 부분의 코드를 실행합니다.
코드에서 비동기 처리부분만 따로 떼어보면, 기존의 프로미스 객체의 them, catch 구문보다 확실히 간결해졌음을 알 수 있습니다.
async function func() {
const promise = new Promise((resolve, reject) => {
setTimeout(()=>{
resolve('await', 1000);
});
});
console.log(await promise);
}
프로미스 객체를 사용할 때는 catch 구문을 사용해서, 프로미스가 reject된 경우를 처리했습니다. 그러나 async
, await
에는 reject되는 경우를 처리하는 구문이 보이질 않습니다.
async
와 await
을 사용할 때 reject는 try~catch
구문으로 처리를 합니다. 비동기 처리 함수 내에서 처리 부분은 try
에 넣고, catch
에 실패 시(=프로미스가 reject인 경우)의 처리를 기술하면 됩니다.
async function func() {
try{
const promise = new Promise((resolve, reject) => {
setTimeout(()=>{
resolve('await', 1000);
});
});
console.log(await promise);
}
catch (e) {
console.log(e);
}
}