이 글을 읽으려면
비동기 처리 및 콜백 함수
와Promise
에 대해 이해하여야한다. 이 부분은 나중에 정리하기로 하자.
async와 await은 자바스크립트의 비동기 처리 패턴 중 가장 최근에 나온 문법이다.
기존의 비동기처리 방식인 콜백함수
와 Promise
의 단점을 보완한 문법이고, Promise
를 좀 더 편하게 사용할 수 있다.
async
함수부터 알아보자, async
는 function 앞에 위치한다.
async function foo(){
return 100;
}
function앞에 async
를 붙이면 해당 함수는 항상 Promise
를 반환한다.
Promise
가 아닌 값을 반환하더라도 이행 상태의 Promise(resolved promise)
로 값을 감싸 이행된 Promise
가 반환되도록 한다.
아래 예시의 함수를 호출하면 result
가 '100'인 이행 Promise
가 반환된다.
async function foo(){
return 100;
}
foo().then(alert); //100
이는 아래와 같이 명시적으로 Promise
를 반환하는것도 가능한데, 결과는 동일하다.
async function foo(){
return Promise.resolve(100);
}
foo().then(alert); //100
async
가 붙은 함수는 반드시Promise
를 반환하고,Promise
가 아닌 것은Promise
로 감싸 반환한다.
await
문법은 다음과 같다
// await은 async 함수 안에서만 동작한다.
const value = await promise
자바스크립트는
await
을 만나면Promise
가 처리(settled)될 때까지 기다리고, 결과는 그 이후 반환된다.
아래 1초 후 이행(완료)되는 Promise
를 예시로 사용하여 await
가 어떻게 동작하는지 살펴보자.
async function foo(){
const promise = new Promise((resolve,reject)=>{
setTimeout(()=>resolve('호출완료!'),1000)
});
const result = await promise; // promise가 이행(완료)될 때까지 기다림(*)
alert(result);
}
foo()// '호출완료!'
함수를 호출하고, 함수 본문이 실행되는 도중 위에 (*)
로 표시한 부분에서 실행이 잠시 '중단' 되었다가 Promise
가 처리되면 실행이 재개된다.
그리고 이때 Promise
객체의 결과 값이 변수 result
에 할당된다.
await('기다리다' 라는 뜻의 영단어 )
는 말 그대로 Promise
가 처리될 때까지 함수 실행을 기다리게 만든다. Promise
가 처리되면 그 결과와 함께 실행이 재개된다.
await
은promise.then
보다 좀 더 세련되게Promise
의 결과 값을 얻게 해주는 문법이다.promise.then
보다 가독성 좋고 쓰기도 쉽다.
await
을 사용할 수 없다.async
함수가 아닌데 await
을 사용하면 문법 에러가 발생한다.function foo(){
const promise = Promise.resolve(1);
const result = await promise; // Syntax Error!!
}
Promise
가 정상적으로 이행(완료)되면 await promise
는 Promise
객체의 result
에 저장된 값을 반환한다.
반면 Promise
가 거부되면 마치 throw
문을 작성한 것처럼 에러가 던져진다.
async function foo(){
await Promise.reject(new Error('에러 발생!!'));
}
위 코드는 아래 코드와 동일하다.
async function foo(){
throw new Error('에러 발생!!');
}
실제 상황에선 Promise
가 거부 되기 전에 약간의 시간이 지체되는 경우가 있다. 이런 경우엔 await
가 에러를 던지기 전에 지연이 발생한다.
await
가 던진 에러는 throw
가 던진 에러를 잡을 때처럼 try..catch
를 사용해 잡을 수 있다.
async function foo(){
try{
const response = await fetch('http://유효하지 않은 주소')
}
catch(err){
alert(err) // TypeError: failed to fetch
}
}
foo();
에러가 발생하면 제어 흐름이 catch 블록으로 넘어간다. 여러 줄의 코드를 try로 감싸는 것도 가능하다.
async function foo(){
try{
const response = await fetch('http://유효하지 않은 주소')
const user = await response.json()
}
catch(err){
// fetch와 response.json에서 발행한 에러 모두를 여기서 잡는다.
alert(err)
}
}
foo();
try..catch
가 없으면 아래 예시의 async
함수 foo()
를 호출해 만든 Promise
가 거부 상태가 된다.
foo()
에 .catch
를 추가하면 Promise
를 처리할 수 있다.
async function foo(){
const response = await fetch('http://유효하지 않은 url')
}
//foo()는 거부 상태의 Promise가 된다.
foo.catch(alert); // TypeError:failed to fetch
.catch
추가하는걸 잊으면, 처리되지 않은 Promise
에러를 발생한다.
☑️
async/await
와promise.then/catch
비교했을때 장점
1.async/await
를 사용하면await
가 대기를 처리해주기 때문에.then
이 필요하지 않다.
2..catch
대신 일반try..catch
를 사용할 수 있다.그렇기에
promise.then
을 사용하는 것 보다async/await
를 사용하는 것이 편리하다.
☑️
async/await
works well withPromise.all
여러개의Promise
가 모두 처리되길 기다려야 하는 상황이라면 이 Promise들을Promise.all
로 감싸고 여기에await
을 붙여 사용할 수 있다.// 프라미스 처리 결과가 담긴 배열을 기다린다. let results = await Promise.all([ fetch(url1), fetch(url2), ... ]);
실패한 프라미스에서 발생한 에러는 보통 에러와 마찬가지로 Promise.all로 전파된다.
에러 때문에 생긴 예외는try..catch
로 감싸 잡을 수 있다.
1. function 앞에 async
키워드를 추가하면 두 가지 효과가 있다.
Promise
를 반환한다.await
를 사용할 수 있다.2. Promise
앞에 await
키워드를 붙이면 자바스크립트는 Promise
가 처리될 때까지 대기한다. 처리가 완료되면 조건에 따라 아래와 같은 동작이 이어진다.
Promise
객체의 result 값을 반환3 .async/await를 함께 사용하면 읽고, 쓰기 쉬운 비동기 코드를 작성할 수 있다.
async/await
를 사용하면 promise.then/catch
가 거의 필요 없다.
하지만 가끔 가장 바깥 스코프에서 비동기 처리가 필요할 때같이 promise.then/catch
를 써야만 하는 경우가 생기기 때문에 async/await
가 프라미스를 기반으로 한다는 사실을 알고 있어야 한다.
여러 작업이 있고, 이 작업들이 모두 완료될 때까지 기다리려면 Promise.all을 활용할 수 있다.
아래 코드를 .then/catch
대신 async/await
를 사용해 다시 작성해보자.
function loadJson(url) {
return fetch(url)
.then(response => {
if (response.status == 200) {
return response.json();
} else {
throw new Error(response.status);
}
})
}
loadJson('no-such-user.json')
.catch(alert); // Error: 404
async function loadJson(url) { // 함수 `loadJson`은 `aync` 함수가 된다.
const response = await fetch(url) // 함수 안의 .then을 전부 await로 바꾼다.
if(response.status == 200){
const json = await response.json()
return json;
}
throw new Error(response.status);
}
loadJson('no-such-user.json')
.catch(alert); // Error: 404 // loadJson에서 던져진 에러는 .catch에서 처리된다.
//loadJson을 호출하는 코드는 async 함수 내부가 아니기 때문에 await loadJson(…)을 사용할 수 없다.
오 나중에 쁘라미스 공부하러 여기 오겠습니다