[js] 이벤트 루프와 비동기 처리
![[js] 이벤트 루프와 비동기 처리](https://cdn.hashnode.com/res/hashnode/image/upload/v1742056868006/458b9d05-f04e-46e1-b720-ef1920aa1fab.png)
JavaScript는 싱글 스레드 기반의 언어로, 한 번에 하나의 작업만 실행할 수 있다. 하지만 브라우저 환경에서는 여러 작업이 동시에 이루어지는 것처럼 보이는데, 어떻게 가능할까? 이는 이벤트 루프와 비동기 처리 덕분이다.
1. JavaScript 실행 방식 (콜 스택)
JavaScript 코드는 콜 스택이라는 곳에서 실행된다. 콜 스택은 LIFO (Last In, First Out) 구조로, 가장 나중에 들어온 작업이 먼저 처리된다.
예제 1: 동기 코드 실행
console.log("A");
console.log("B");
console.log("C");
출력 결과:
A
B
C
이처럼 코드가 순차적으로 실행된다.
2. 콜 스택이 블로킹되는 문제
만약 오래 걸리는 작업이 있다면, 콜 스택이 이 작업을 실행하느라 다른 작업을 할 수 없게 된다.
console.log("A");
for (let i = 0; i < 10000000000; i++) {} // 무거운 연산
console.log("B");
이 경우 브라우저가 멈춘 것처럼 보이는데, 이는 콜 스택이 연산을 수행하느라 다른 작업을 할 수 없기 때문이다.
3. Web API와 비동기 처리
Web API란?
Web API는 브라우저가 제공하는 API 로, JavaScript가 단독으로 처리할 수 없는 기능들을 수행할 수 있도록 도와준다. 즉, 브라우저가 제공하는 기능을 활용해 JavaScript가 네트워크 요청, 타이머 설정, DOM 조작, 이벤트 리스너 등 다양한 작업을 할 수 있게 된다.
Web API의 대표적인 예는 다음과 같다:
DOM: HTML 요소를 조작하는 API
Fetch API / XMLHttpRequest: 네트워크 요청을 처리하는 API
setTimeout / setInterval: 일정 시간이 지난 후 실행되는 타이머 API
Geolocation API: 사용자의 위치 정보를 가져오는 API
Web Storage: 브라우저에 데이터를 저장하는 API
Web API와 이벤트 루프의 관계
JavaScript는 비동기 함수를 실행할 때 Web API를 활용한다.
예제 2: 비동기 코드 (setTimeout)
console.log("hi");
setTimeout(() => {
console.log("there");
}, 5000);
console.log("bye");
출력 결과:
hi
bye
there (5초 후 출력)
실행 과정:

console.log("hi")→ 콜 스택에서 실행 후 제거setTimeout()→ Web API로 넘겨 처리 (5초 대기 후 실행 예정)console.log("bye")→ 콜 스택에서 실행 후 제거5초 후,
setTimeout의 콜백이 콜백 큐에 저장됨이벤트 루프가 콜 스택이 비었는지 확인 후, 콜백을 가져와 실행
console.log("B")실행
4. 이벤트 루프(Event Loop)
이벤트 루프는 콜 스택과 콜백 큐를 감시하면서 작업을 관리하는 역할을 한다.
콜 스택이 비어 있을 때만 콜백 큐에서 작업을 가져와 실행한다.
이 덕분에 비동기 작업이 완료된 후에도 프로그램이 멈추지 않고 계속 실행될 수 있다.
5. 마이크로태스크 큐 (Microtask Queue)
비동기 작업에는 콜백 큐 외에도 마이크로태스크 큐가 있다.
console.log("A");
setTimeout(() => {
console.log("B");
}, 0);
Promise.resolve().then(() => {
console.log("C");
});
console.log("D");
출력 결과:
A
D
C
B
실행 과정:
console.log("A")실행setTimeout()실행 → Web API로 넘겨 타이머 시작 (콜백 큐 대기)Promise.resolve().then()실행 → 마이크로태스크 큐로 이동console.log("D")실행 (동기 코드 실행)마이크로태스크 실행 →
console.log("C")콜백 큐 실행 →
console.log("B")
✅ 마이크로태스크(Promise, async/await)가 콜백 큐(setTimeout, setInterval)보다 먼저 실행된다!
6. async/await과 이벤트 루프
async/await 도 결국 Promise 기반의 비동기 코드이다.await 키워드는 비동기 작업이 끝날 때까지 기다렸다가 실행을 계속하는 역할을 한다.
예제 3: async/await의 실행 순서
console.log("A");
async function fetchData() {
console.log("B");
await Promise.resolve();
console.log("C");
}
fetchData();
console.log("D");
출력 결과:
A
B
D
C
실행 과정:
console.log("A")실행fetchData()실행 →console.log("B")await Promise.resolve();→ 마이크로태스크 큐로 이동console.log("D")실행 (동기 코드 먼저 실행)마이크로태스크 실행 →
console.log("C")
7. 정리
✅ JavaScript는 싱글 스레드이지만, Web API와 이벤트 루프를 활용해 비동기 작업을 처리할 수 있다. ✅ 비동기 작업이 완료되면 콜백 큐나 마이크로태스크 큐에 등록되고, 이벤트 루프가 이를 실행한다. ✅ 마이크로태스크(Promise, async/await)가 콜백 큐(setTimeout, setInterval)보다 먼저 실행된다.
💡 결론:
JavaScript는 싱글 스레드이지만 이벤트 루프 덕분에 마치 멀티태스킹처럼 동작한다! 🚀