async/await
async/await는 ES8에서 도입된 문법으로, 비동기 작업을 마치 동기적인 코드처럼 작성할 수 있게 해주어 가독성을 높이고, 비동기 작업의 흐름을 직관적으로 이해할 수 있도록 도와줍니다.
async
async 함수는 언제나 프로미스를 반환합니다. 명시적으로 프로미스를 반환하지 않는 경우에도 async 함수는 암묵적으로 반환값을 resolve하는 프로미스를 반환합니다.
await
await 키워드는 프로미스가 settled 상태(비동기 처리가 수행된 상태)가 될 때까지 대기하다가 처리 결과를 반환합니다. await 키워드는 반드시 프로미스 앞에서 사용해야 하며, async 함수 내부에서 사용해야 합니다.
실행 컨텍스트로 살펴보기
샘플 코드
async function C() {
console.log("C 시작");
const result = await fetchData();
console.log("C 재개", result);
return `${result} from func C`;
}
async function B() {
console.log("B 시작");
const result = await C();
console.log("B 재개", result);
}
B();
console.log("전역 실행");
async function fetchData() {
return new Promise((resolve) => {
setTimeout(() => resolve("someResult"), 1000);
});
}
실행 컨텍스트로 살펴보기
[4] 함수 fetchData 실행 컨텍스트
[3] 함수 C 실행 컨텍스트(일시 중단)
[2] 함수 B 실행 컨텍스트(일시 중단)
[1] 전역 컨텍스트
- 함수 fetchData 가 실행되는 순간, 콜 스택에는 다음 4가지 실행 컨텍스트가 푸시된 상태입니다.
- 함수 fetchData는 비동기이기 때문에 실행 후 바로 제거되고, Node API 로 넘어갑니다.
- await 를 만나면 해당 실행 컨텍스트는 일시 중지됩니다.
- await C()를 만난 함수 B의 실행 컨텍스트는 일시 중단된 상태가 됩니다.
- await fetchData()를 만난 함수 C의 실행 컨텍스트 또한 일시 중단된 상태가 됩니다.
- 이렇게 되면 실행 중인 실행 컨텍스트는 전역 컨텍스트가 됩니다.
- 전역 코드인 console.log(”전역 실행”) 이 실행되며 콜스택이 완전히 비워집니다
[2] C 실행 재개
[1] 전역 컨텍스트
- Node API에서 완료된 fetchData()의 Promise가 fulfilled 상태가 되는 순간, 자바스크립트 엔진(V8 엔진)에 의해 마이크로태스크 큐에 "C 함수 재개" 실행 컨텍스트를 등록됩니다.
- 콜스택이 비어 있는 상태이기 때문에 이벤트루프는 마이크로태스크 큐에서 C 함수 재개 실행 컨텍스트를 가져와서 콜스택에 푸시합니다.
[1] 전역 컨텍스트
- console.log("C 재개", result); 코드가 실행됩니다.
- 이어서 C가 리턴을 하며 Promise가 fulfilled 상태가 되고, "B 실행 재개" 실행 컨텍스트가 마이크로태스크 큐에 등록됩니다.
- 이어서 C 실행 재개 실행 컨텍스트가 팝됩니다.
[2] B 실행 재개
[1] 전역 컨텍스트
- 실행 중인 실행 컨텍스트가 종료되었으므로, 이벤트 루프는 마이크로태스크큐에서 B 함수 재개 실행 컨텍스트를 가져옵니다.
- console.log("B 재개", result); 코드가 실행되며 B 실행 재개 실행 컨텍스트가 팝되고, 전역 컨텍스트도 제거되며 콜스택이 완전히 비워지게 됩니다.
비동기 작업에서 Node API와 이벤트 루프의 역할
Promise, setTimeout 등 비동기 작업에서 Node API와 이벤트 루프의 역할이 각기 다릅니다.
Node API
먼저, 비동기 작업의 처리는 Node API가 담당합니다. Node API는 단순히 비동기 작업을 처리하고, 완료된 작업을 마이크로태스크 큐 또는 태스크 큐로 보내는 것은 자바스크립트 엔진이 담당합니다. 자바스크립트 엔진은 Promise의 상태 변화를 감지하는데, then() 후속 메서드 또는 await가 걸려 있는 작업을 추적하고 있다가 fulfilled 상태가 되면 해당 콜백을 마이크로태스크 큐에 등록합니다.
이벤트 루프
이벤트 루프는 큐에 있는 작업들을 콜 스택에 푸시하는 역할을 합니다. 이때 태스크 큐 보다 마이크로태스크 큐가 우선순위를 갖습니다. 일반적으로 태스크 큐는 콜 스택이 완전히 비워졌을 때 실행되지만, 마이크로태스크 큐는 콜 스택이 완전히 비워지지 않아도 await 를 만나서 실행 컨텍스트가 중단되거나 함수가 끝났을 때 실행됩니다.
'Language > JavaScript' 카테고리의 다른 글
변수 (0) | 2025.03.10 |
---|---|
프로토타입 (0) | 2025.03.08 |
제너레이터 - 이터러블/ 이터레이터 (0) | 2025.02.20 |
Promise 개념 살펴보기(비동기, 힙메모리, 마이크로태스크 큐) (0) | 2025.02.12 |
실행 컨텍스트 뿌시기 part2 (0) | 2023.08.27 |