1. 개요
JavaScript는 싱글 스레드(single-thread) 기반 언어로, 하나의 실행 컨텍스트에서 코드가 순차적으로 실행된다. 하지만 **비동기 작업(Asynchronous Task)**을 효율적으로 처리하기 위해 **이벤트 루프(Event Loop)**라는 메커니즘을 사용한다.
이벤트 루프는 비동기 코드(예: setTimeout, fetch, Promise 등)가 실행될 때, 어떻게 처리되는지 결정하는 핵심 개념이다. 본 글에서는 이벤트 루프의 원리와 함께 **비동기 처리 방식(콜백, 프로미스, async/await)**에 대해 알아본다.
2. JavaScript의 실행 방식
(1) 싱글 스레드 모델
JavaScript는 기본적으로 싱글 스레드 환경에서 동작하며, 한 번에 한 가지 작업만 실행할 수 있다.
출력 결과는 다음과 같다.
이처럼 setTimeout이 지정된 시간 후에 실행되는 이유는 이벤트 루프와 태스크 큐(Task Queue)가 존재하기 때문이다.
(2) 실행 컨텍스트(Execution Context)와 콜 스택(Call Stack)
JavaScript 코드는 실행될 때 **실행 컨텍스트(Execution Context)**가 생성되며, 이 컨텍스트는 **콜 스택(Call Stack)**에 저장된다.
실행 과정:
- second()가 호출되면 second 실행 컨텍스트가 콜 스택에 추가됨
- console.log("Second") 실행 후, first() 호출
- first 실행 컨텍스트가 콜 스택에 추가됨
- console.log("First") 실행 후 first 컨텍스트 제거
- second 실행 컨텍스트도 제거
출력 결과:
이처럼 JavaScript는 콜 스택을 사용하여 동기적으로 코드 실행을 관리한다.
3. 이벤트 루프(Event Loop)란?
이벤트 루프(Event Loop)는 콜 스택과 태스크 큐(Task Queue)를 모니터링하며, 스택이 비면 대기 중인 비동기 작업을 실행하는 역할을 한다.
(1) 이벤트 루프의 동작 원리
- 콜 스택이 비어 있는지 확인
- 태스크 큐에서 대기 중인 작업이 있는지 확인
- 콜 스택이 비어 있으면 태스크 큐에서 작업을 꺼내 실행
출력 결과:
(2) 태스크 큐(Task Queue)와 마이크로태스크 큐(Microtask Queue)
비동기 작업은 태스크 큐(Task Queue) 또는 **마이크로태스크 큐(Microtask Queue)**에 추가된다.
- 태스크 큐(Task Queue): setTimeout, setInterval, fetch 응답 등이 여기에 저장됨
- 마이크로태스크 큐(Microtask Queue): Promise.then(), queueMicrotask() 등이 여기에 저장됨
마이크로태스크가 항상 우선 실행된다.
출력 결과:
마이크로태스크(Promise.then())가 태스크 큐(setTimeout)보다 먼저 실행된다.
4. 비동기 처리 방법
(1) 콜백(Callback) 함수
콜백은 비동기 작업이 완료된 후 실행되는 함수다.
콜백 방식은 단순하지만, 콜백 지옥(Callback Hell) 문제를 유발할 수 있다.
콜백 중첩이 깊어지면 코드 가독성이 떨어진다.
(2) 프로미스(Promise) 사용
Promise는 비동기 작업을 보다 구조적으로 처리할 수 있는 객체다.
프로미스를 사용하면 **체이닝(Promise Chaining)**이 가능하다.
(3) async/await 사용
async/await는 프로미스를 기반으로 동작하는 문법으로, 코드를 동기적으로 작성할 수 있도록 도와준다.
✅ async/await를 사용하면 코드를 보다 직관적으로 작성할 수 있다.
5. 이벤트 루프 최적화 및 활용 전략
(1) 태스크 큐 지연 최소화
비동기 작업이 너무 많으면 이벤트 루프가 지연될 수 있다. 불필요한 타이머(setTimeout) 사용을 줄이는 것이 중요하다.
대신, requestAnimationFrame 또는 queueMicrotask를 활용하면 더 빠르게 실행할 수 있다.
(2) 무거운 작업을 Web Worker로 분리
CPU 집약적인 작업은 Web Worker를 사용하여 이벤트 루프를 차단하지 않도록 한다.
(3) await 남용 방지
await를 남발하면 코드 실행이 차례로 진행되므로, 병렬 실행이 가능할 경우 Promise.all()을 활용한다.
6. 결론
JavaScript의 이벤트 루프는 비동기 작업을 효율적으로 처리하는 핵심 메커니즘이다.
✅ 핵심 요약
- JavaScript는 싱글 스레드지만 이벤트 루프를 통해 비동기 처리 가능
- 비동기 작업은 **태스크 큐(Task Queue) 또는 마이크로태스크 큐(Microtask Queue)**에서 관리됨
- setTimeout보다 Promise.then()이 먼저 실행됨
- async/await을 활용하면 비동기 코드를 보다 가독성 좋게 작성 가능
이벤트 루프를 이해하면 JavaScript의 비동기 실행 원리를 보다 효율적으로 활용할 수 있다.
'IT & 웹개발' 카테고리의 다른 글
JavaScript 클로저(Closure) 완벽 가이드 (0) | 2025.04.02 |
---|---|
함수형 프로그래밍과 JavaScript – 개념 및 예제 (0) | 2025.04.02 |
JavaScript 메모리 관리와 가비지 컬렉션(Garbage Collection) 이해하기 (0) | 2025.04.02 |
TypeScript 도입 시 고려해야 할 점 및 장단점 (0) | 2025.04.02 |
JavaScript 비동기 처리 – 콜백, 프로미스, async/await (0) | 2025.04.02 |