JavaScript는 비동기 작업(ajax요청, eventListener 등)을 효율적으로 처리하기 위해 async와 await 키워드를 제공하는데,
이 문법을 사용하면 복잡한 비동기 코드 흐름을 동기 코드처럼 간결하게 작성할 수 있다.
async 함수async 키워드는 함수 선언 앞에 붙여 사용하며, 이 함수가 비동기 함수임을 나타낸다.
비동기 함수는 항상 Promise를 반환하며, 함수 내에서 명시적으로 값을 반환하면 자동으로 그 값이 Promise.resolve로 감싸져 반환된다.
async function fetchData() {
return "Data fetched";
}
// 호출 시 Promise가 반환됨
fetchData().then(data => console.log(data)); // "Data fetched"
await 키워드await 키워드는 async 함수 내에서만 사용 가능하며, Promise가 처리될 때까지 함수의 실행을 일시 중지시킨다.
이때 Promise가 해결되면, await은 그 Promise의 결과를 반환해준다.
async function fetchData() {
let data = await fetch("https://api.example.com/data");
return data.json();
}
async function processData() {
let result = await fetchData();
console.log(result);
}
위 흐름은
| 단계 | 설명 |
|---|---|
| 1단계 | fetchData() 호출 → async 함수이므로 즉시 Promise 반환 |
| 2단계 | fetch(...)는 Promise 반환 → await가 응답을 기다림 |
| 3단계 | 응답 완료 후 response 변수에 할당 |
| 4단계 | response.json() 또한 Promise → 다시 await으로 대기 |
| 5단계 | 최종적으로 JSON 파싱 완료 → data 반환됨 |
가독성 : 복잡한 비동기 처리 로직을 동기 코드처럼 작성할 수 있어 코드 가독성이 크게 향상된다.
에러 처리 : 비동기 코드에서 발생하는 예외를 try ~ catch 구문을 통해 처리할 수 있다.
순차적 실행 : await 키워드를 사용해 비동기 작업을 순차적으로 실행할 수 있다.
비슷한 구문이지만 차이점이 존재한다.
| 항목 | Promise.then() | async / await |
|---|---|---|
| 코드 가독성 | 중첩 또는 체이닝 발생 | 동기 코드처럼 순차적으로 읽힘 |
| 에러 처리 방식 | .catch()로 처리 | try ~ catch 블록 사용 가능 |
| 흐름 파악의 용이성 | 흐름이 복잡해질 수 있음 | 위에서 아래로 읽는 자연스러운 흐름 |
| 디버깅 | 스택 추적 어려움 | 더 직관적인 디버깅 가능 |
JavaScript의 fetch()는 404, 500 등의 HTTP 오류 응답도 Promise를 resolve하므로
에러는 직접 체크해야 한다.
async 함수 내에서 발생한 에러는 try ~ catch 블록을 사용하여 처리할 수 있다.
await이 있는 코드에서 에러가 발생하면, 그 에러는 catch 블록으로 전달된다.
async function fetchData() {
try {
const response = await fetch("https://api.example.com/data");
if (!response.ok) {
// HTTP 상태코드 오류일 경우
throw new Error("Network response was not ok");
}
const data = await response.json();
return data;
} catch (error) {
console.error("❌ Fetch error:", error);
// 사용자에게 알림을 주거나 재시도 로직 추가 가능
}
}