async라는 이름이 만드는 오해
자바스크립트의 async function을 보면 자연스럽게 "이 코드는 비동기로 동작하는구나"라고 생각하게 된다. 하지만 실제로 실행 흐름을 뜯어보면, async라는 키워드 자체는 비동기 실행을 보장하지 않는다. 진짜 비동기 전환을 일으키는 건 async가 아니라 그 안에 있는 await이다. 이 글에서는 코드로 그 근거를 하나씩 확인한다.
await 없는 async 함수는 동기로 동작한다
다음 코드를 실행해보자.
console.log('A');
async function asyncFunc() {
console.log('B'); // await 없음
}
asyncFunc();
console.log('C');
결과는 A → B → C 순서다. asyncFunc()를 호출하는 순간 함수 본문이 즉시 실행되고, 안에 await이 하나도 없으니 끝까지 멈추지 않고 그대로 실행된다. 호출자(메인 흐름)는 asyncFunc()가 완전히 끝난 뒤에야 다음 줄(C)로 넘어간다. 일반 동기 함수를 호출한 것과 실행 순서가 완전히 동일하다.
진짜 비동기 전환은 await이 만든다
이번엔 await을 넣어보자.
console.log('A');
async function asyncFunc() {
await delay(1000); // 여기서 멈춤
console.log('B');
}
asyncFunc();
console.log('C');
결과는 A → C → (1초 후) B로 바뀐다. await을 만나는 순간 함수 실행이 그 자리에서 중단되고, 제어권이 호출자에게 즉시 반환된다. 그래서 C가 먼저 찍히고, 대기 중이던 작업이 끝나면 그제서야 B가 재개되어 실행된다.
즉 async function은 await을 쓸 수 있게 해주는 문법적 장치일 뿐이고, 함수 실행이 동기 구간과 비동기 구간으로 나뉘는 기준은 await을 실제로 만나는 지점이다. await 이전 줄들은 동기로 실행되고, await 이후부터 비로소 비동기로 동작한다. async라는 이름값과 달리, 비동기 여부를 결정하는 주어는 await이지 async가 아니다.
이건 자바스크립트만의 특이한 동작이 아니다. 코틀린의 async { }도 Deferred라는, Promise에 대응하는 비동기 객체를 반환하는데, 내부에 delay() 같은 suspend 함수를 실제로 만나기 전까지는 그냥 동기적으로 실행된다. "실행 지점까지는 동기, 대기 지점 이후에만 비동기"라는 같은 원리다. 반대로 자바의 CompletableFuture는 supplyAsync()를 호출하는 순간 애초에 별도 스레드로 작업이 위임되기 때문에, 이런 대기 지점 없이도 호출 즉시 항상 비동기로 동작한다. async/await 같은 "제어권을 넘기는 지점"이 필요한 모델과, 처음부터 별도 스레드로 갈라지는 모델은 이렇게 서로 다르다.
반환값은 여전히 Promise다: 실행과 소비는 다른 문제
여기서 한 가지 짚을 부분이 있다. await이 없어도 async function은 자바스크립트의 Promise라는 비동기 객체를 반환한다.
async function foo() {
return 1; // await 없음
}
console.log('X');
foo().then(v => console.log('Y', v));
console.log('Z');
결과는 X → Z → Y 1이다. foo() 본문 실행 자체는 완전히 동기적으로 끝났지만, 그 결과를 꺼내 쓰는 .then() 콜백은 Promise가 이미 resolve된 상태여도 반드시 마이크로태스크 큐를 거쳐야 하므로 항상 비동기로 실행된다.
정리하면 함수 본문의 실행(await 없으면 동기)과 반환된 Promise의 결과 소비(then 호출 자체는 항상 비동기)는 서로 다른 층위의 이야기다.
정리
async라는 이름은 비동기를 보장하는 키워드가 아니다. 함수가 실제로 비동기로 동작하는지는 await이 있는지, 그리고 그 지점을 실제로 통과했는지에 달려 있다. 대기 지점을 만나기 전까지는 async 함수도 그냥 동기 코드와 동일하게 실행된다.
'🕸웹 > 🟨JavaScript' 카테고리의 다른 글
| [Node.js] 실무에서는 사용하지 않는 바닐라(순수) Node.js 서버 (0) | 2024.12.16 |
|---|---|
| [Node.js] 바닐라 Node.js, Express, NestJS 서버 및 코드 비교 (0) | 2024.12.11 |
| [React] JSX 문법 한 번에 정리하기 (4) | 2024.12.02 |
| npm 주요 명령어 정리 (0) | 2024.11.28 |
| 리액트 라우터 개념과 설정 방법 (1) | 2024.11.25 |