JavaScript는 싱글 스레드 언어임에도 비동기 작업을 효과적으로 처리할 수 있는 구조를 가지고 있으며, 그 핵심에는 이벤트 루프(Event Loop)가 있다.
이벤트 루프의 작동 원리와 주요 비동기 처리 방식인setTimeout,Promise,async/await까지 개념과 주의사항에 대해 알아보자.
JavaScript는 싱글 스레드 기반으로 동작한다.
즉, 한 번에 하나의 작업만 처리할 수 있기 때문에 I/O 작업(네트워크, 파일, 타이머 등)을 동기적으로 처리하면 전체 프로그램이 멈추게 된다.
이를 해결하기 위해 비동기 처리가 도입되었고, 이벤트 루프는 이를 가능하게 하는 핵심 메커니즘이다.
JavaScript 실행 환경(예: 브라우저, Node.js)은 다음과 같은 구성 요소로 이루어져 있다.
setTimeout, fetch, DOM 이벤트 등 브라우저가 제공하는 비동기 APIPromise.then, queueMicrotask 등의 마이크로태스크 대기열setTimeout브라우저의 Web API를 통해 타이머를 설정한 뒤, 지정 시간 이후 콜백을 큐에 넣는다.
console.log('시작');
setTimeout(() => {
console.log('1초 뒤 실행');
}, 1000);
console.log('끝');
👀 출력 순서
시작
끝
1초 뒤 실행
설정한 시간이 지난 직후 실행된다는 보장은 없음 → 이벤트 루프가 빈 상태여야 실행된다.
비동기 작업의 결과를 표현하는 객체.
생성 시 바로 실행되며, 완료되면 Microtask Queue에 콜백을 넣는다.
console.log('시작');
Promise.resolve().then(() => {
console.log('Promise');
});
console.log('끝');
👀 출력 순서
시작
끝
Promise
then/catch/finally는 마이크로태스크로 처리되며 setTimeout보다 우선이다.
Promise를 더 읽기 쉬운 방식으로 작성하게 해주는 문법적 설탕(Syntax Sugar).
async function fetchData() {
console.log('fetch 시작');
const res = await Promise.resolve('응답');
console.log(res);
}
fetchData();
console.log('동기 코드 실행');
👀 출력 순서
fetch 시작
동기 코드 실행
응답
await은 해당 Promise가 resolve될 때까지 기다리고, 이후의 코드를 마이크로태스크로 밀어넣는다.
setTimeout 최소 지연 시간브라우저에서는 setTimeout(fn, 0)이라도 최소 4ms의 지연이 발생할 수 있다. (특히 오래된 브라우저)
동기 함수 내에서 시간이 오래 걸리는 코드를 작성하면 이벤트 루프가 막혀 전체 UI가 멈춘다.
while (true) {} // 🚫 절대 ㄴㄴ 🚫
Promise는 자동으로 예외를 캡처하지 않음async function broken() {
throw new Error('실패');
}
broken(); // 처리되지 않은 Promise 예외 발생
// 반드시 처리
broken().catch(console.error);
| 상황 | 추천 방식 | 비고 |
|---|---|---|
| 간단한 지연 | setTimeout | 타이머 기반 지연 |
| 네트워크 요청 등 외부 작업 처리 | Promise | .then(), .catch() 활용 |
| Promise 기반 코드 간결하게 작성 | async/await | try/catch와 함께 사용 권장 |
| 여러 비동기 작업 병렬 실행 | Promise.all() | 병렬 처리 및 실패 관리 필요 |
| 이벤트 루프 흐름 실험 및 디버깅 | console.log, setTimeout, Promise 조합 | 실행 순서 분석에 도움 |