Promise로 비동기 처리를 깔끔하게 할 수 있게 됐지만, `then()`이 여러 개 이어지면 여전히 길고 귀찮음
`async / await`을 이용하면 비동기 코드를 동기 코드처럼 한 줄씩 읽을 수 있게됨
1. `async`
`async`는 "이 함수는 비동기 함수야"라고 표시하는 키워드임
내부에서 자동으로 Promise를 반환함
async function getData() {
return {
name: "도서",
id: "doseo",
};
}
console.log(getData());
// Promise { <fulfilled>: { name: "도서", id: "doseo" } }
- `async` 함수는 무조건 Promise를 반환함
- 함수 내부에서 return으로 값을 주면, 그게 자동으로 `reslove()`에 담겨 나감
- 즉 이건 아래 코드와 같음
function getData() {
return Promise.resolve({
name: "도서",
id: "doseo",
});
}
2. `async`함수가 Promise를 반환하는 이유
Promise로 감싸면 나중에 `.then()`이나 `await`으로 결과를 기다릴 수 있기 때문임
즉, `async`는 비동기 작업을 "Promise 기반"으로 자동으로 감싸주는 문법임
async function getData1() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
name: "이도서",
id: "leedoseo",
});
}, 2000);
});
}
console.log(getData1()); // Promise { <pending> }
- 이건 직접 Promise를 반환하는 함수라서 `async`는 사실상 큰 역할은 안함
- 그래도 `async`를 붙이면 이 함수가 "비동기 함수"라는 것을 명확히 보여줄 수 있음 (내 생각에는 굳이..?)
3. `await`
`await`은 Promise가 처리될 때까지 기다렸다가, 결과값을 변수에 담음
단, `await`은 반드시 `async` 함수 안에서만 사용 가능함
기존 Promise 체이닝으로 쓰면
function printData() {
getData1().then((result) => {
console.log(result);
});
}
printData();
// (2초 후)
// { name: "이도서", id: "leedoseo" }
이 코드를 `async / await`을 사용하면?
async function printData() {
const data = await getData1();
console.log(data);
}
printData();
// (2초 후)
// { name: "이도서", id: "leedoseo" }
코드가 단순해짐!
- `await getData1()`은 "getData1`()의 Promise가 끝날 때까지 잠깐 기다림"이라는 뜻
- JS는 여기서 일시정지하고, Promise가 완료되면 `data`에 결과를 넣고 다음 줄 실행
- 비동기인데 마치 동기처럼 한 줄씩 읽히는게 핵심!
4. Promise 체이닝 VS `async / await`
이전 시간에 사용했던 `add10`을 예시로 들어보겠음
// Promise 체이닝
add10(0)
.then((result) => {
console.log(result); // 10
return add10(result);
})
.then((result) => {
console.log(result); // 20
return add10(result);
})
.then((result) => {
console.log(result); // 30
return add10(undefined);
})
.catch((error) => {
console.log(error); // num이 숫자가 아님
});
- `.then()`은 앞의 `resolve` 결과를 다음 단계로 넘겨줌
- 에러 발생 시 `.catch()`에서 한 번에 처리
- 콜백보단 깔끔하지만, `.then()`이 많아지면 가독성이 떨어짐
// async / await
async function runAdd10() {
try {
let result = await add10(0);
console.log(result); // 10
result = await add10(result);
console.log(result); // 20
result = await add10(result);
console.log(result); // 30
result = await add10(undefined);
console.log(result);
} catch (error) {
console.log(error); // num이 숫자가 아님
}
}
runAdd10();
- `await`은 Promise가 끝날 때까지 기다렸다가 결과를 반환
- 순서가 자연스럽게 위 -> 아래로 이어짐
- 에러도 `try / catch`로 한 번에 처리 가능
- 동기 코드처럼 읽혀서 가독성이 좋음
근데, 아직도 차이를 잘 모르겠다면 사람의 말로 번역해 보겠음
Promise 체이닝은
“add10(0)을 실행하고 결과 나오면 다음 then 실행,
그 다음 결과 나오면 또 다음 then 실행,
그 다음 결과 나오면 또 다음 then 실행,
중간에 실패하면 catch로 이동.”
한 줄 한 줄이 "이 일이 끝나면 다음 일 해"라는 구조로
우리가 생각하는 순서와 코드의 순서가 좀 다름
`async / await`은
“add10(0) 결과 기다려서 result에 넣고 → 출력하고,
add10(result) 결과 기다려서 → 출력하고,
add10(result) 또 기다려서 → 출력하고,
마지막엔 add10(undefined) 하다가 에러 나면 catch로 이동.”
순서대로 진행되는 코드 처럼 읽힘
아직은 공부 단계라 실전으로 사용해보진 못했는데,
실전에서 사용해보다가 막히는 부분이나 공유하면 좋을 것 같은게 있다면 추가로 작성해보겠음
'React > JavaScript 심화' 카테고리의 다른 글
| [JavaScript 심화] 고차함수 총정리(복습) (0) | 2025.12.03 |
|---|---|
| [JavaScript 심화] 비동기 - Promise (0) | 2025.11.11 |
| [JavaScript 심화] 비동기 - 콜백 함수 (0) | 2025.11.11 |
| [JavaScript 심화] 동기와 비동기 (0) | 2025.11.11 |
| [JavaScript 심화] Date 객체 (0) | 2025.11.11 |