자바스크립트가 비동기 처리가 가능하다는 사실은 당연히 알고 있었지만
어떤 원칙으로 어떤 구성으로 돌아가는지 제대로 모르고 있는 것 같아서 정리해보고자 한다 ^__^
자바스크립트는 싱글 스레드 언어인데 어떻게 동시에 일을 진행시키는지 알아보자.
📚 동기(Synchronous)와 비동기(Asynchronous)

1. 동기
일반적으로 각 함수와 코드들이 위에서 아래로 차례로 동작하는 방식이 동기이다. 즉, 이전 작업이 완료되어야 다음 작업을 수행할 수 있다. 동기 방식은 간단하고 직관적이지만, 작업이 오래 걸리거나 응답이 늦어지는 경우에는 전체적인 성능과 사용자 경험에 영향이 간다.
2. 비동기
특정 작업의 완료를 기다리지 않고 다른 작업을 동시에 수행하도록 하는 방식이 비동기이다. 비동기는 메인 스레드가 작업을 다른 곳에 인가하여 처리하게 되고, 그 작업이 완료되면 콜백 함수를 받아 실행하는 방식으로 작업을 백그라운드에 요청하여 처리되게 하여 멀티로 작업을 동시에 처리하는 것이다. 즉, 특정 코드의 연산이 끝날 때까지 코드의 실행을 멈추지 않고 다음 코드를 먼저 실행한다.
🤔 자바스크립트는 싱글스레드가 맞을까?
🅾️ 결론부터 말하자면 자바스크립트는 싱글스레드 기반 언어이다.
자바스크립트 엔진은 단 하나의 실행 컨텍스트 스택을 가지고 있다.
이는 함수를 실행할 수 있는 창구가 단 하나이며, 동시에 2개 이상의 함수를 실행할 수 없다는 것을 뜻한다.
이처럼 자바스크립트 엔진은 한번에 하나의 태스크만 실행할 수 있는 싱글스레드 방식으로 동작한다.
싱글 스레드 방식은 한번에 하나의 태스크만 실행할 수 있기 때문에 처리에 시간이 걸리는 태스크를 실행하는 경우 블로킹이 발생한다.
싱글 스레드는 위에서 아래로 실행되는 동기 처리 방식을 지니고 있다.
function first() {
setTimeout(() => {
console.log("first")
},1000)
}
function second() {
setTimeout(() => {
console.log("second")
},500)
}
first()
second()
이 예제를 생각해보면 동기적인 실행이라면 1초가 지나고 first가 찍히고, 1.5초가 지나고 second가 찍혀야한다.
그런데 실제로 위의 코드를 실행해보면 0.5초 후에 second가 실행되고 1초 후에 first가 실행된다.
싱글스레드 기반인 자바스크립트에서 어떻게 이런 결과가 나오는 걸까?
💡 비동기 작업이 가능한 이유
자바스크립트 엔진은 싱글 스레드라 한번에 한 작업만 실행한다.
그럼에도 비동기가 가능한 이유는 브라우저가 타이머, 네트워크, DOM 이벤트 같은 일을 백그라운드에서 처리하고
작업이 끝나면 콜백을 큐에 등록하기 때문이다. 이후 이벤트 루프가 메인 스레드가 비는 순간 그 콜백을 꺼내서 실행한다.
즉, 자바스크립트 코드가 동시에 실행되는 건 아니고, 동시에 되는 것처럼 보이는 동시성을 얻는 것이다.
✨ 이벤트 루프
자바스크립트는 기본적으로 싱글 스레드로 실행되며, 브라우저의 이벤트 루프가 실행 순서를 조율한다.
메인 스레드(콜 스택)이 비었을 때, 콜백 큐에서 대기중인 함수를 콜 스택으로 불러와 실행시키는 역할을 한다.
따라서 이벤트 루프는 콜스택에 현재 실행중인 작업이 있는지, 그리고 태스크 큐에 대기 중인 작업이 있는지 반복적으로 확인하는 일종의 무한 루프 작업을 진행하고, 대기 작업이 있다면 작업을 옮겨주는 형태로 동작한다고 볼 수 있다.

setTimeout이나 AJAX 같은 비동기 함수가 호출되면, 해당 작업은 브라우저의 Web APIs에서 백그라운드로 처리된다.
작업이 완료되면 해당 콜백이 큐에 등록되고, 이벤트 루프는 콜 스택이 비어있는 경우를 탐지하여 태스크 큐에 있는 콜백 함수를 콜 스택으로 옮겨 실행시킨다. 비동기 함수가 동기 함수들과 동시에 동작하는 것처럼 보이지만, 아주 재빠르게 콜 스택에 넘어와 실행 되었기 때문에 이 시간 차가 너무 작아서 동시에 돌아간다고 착각을 하는 것이다.
⚡️ 매크로태스크 큐와 마이크로태스크 큐

자바스크립트의 태스크 큐는 크게 매크로태스크 큐와 마이크로태스크 큐로 나뉜다.
이 큐들은 비동기 작업의 우선순위를 관리하고, 이벤트 루프가 적절한 시점에 콜백을 실행하기 위해 사용된다.
매크로태스크 큐
매크로태스크 큐는 일반적인 비동기 작업의 콜백이 저장되는 큐이다.
setTimeout, setInterval, I/O 작업, 이벤트 핸들러 등은 작업 완료 후 매크로태스크 큐에 콜백을 대기시킨다.
매크로태스크 큐는 이벤트 루프의 한번의 반복마다 하나의 태스크만 처리되므로, UI업데이트나 다른 작업과 균형 있게 진행된다.
마이크로태스크 큐
마이크로태스크 큐는 더 높은 우선순위가 필요한 비동기 작업들이 대기하는 큐이다.
Promise.then, MutationObserver 등의 비동기 콜백이 여기에 저장된다.
이벤트 루프는 매크로태스크를 실행하기 전에 항상 마이크로태스크 큐를 먼저 확인하고, 모든 마이크로태스크를 처리한 후 매크로태스크로 넘어간다. 이 방식으로 마이크로태스크 큐의 작업은 높은 우선순위로 처리된다.
참고문헌
https://www.eunbinyeon.com/blog/how-javascript-single-thread-handles-asynchronous-tasks
https://stitchcoding.tistory.com/44
'JavaScript' 카테고리의 다른 글
| [JavaScript] JavaScript의 비동기 프로그래밍 ( 콜백함수, Promise , async/await ) (0) | 2025.08.20 |
|---|---|
| [JavaScript] var, let, const를 비교해보자 (재선언, 재할당, 스코프, 호이스팅) (3) | 2025.08.19 |
| [JavaScript] TDZ (Temporal Dead Zone) 이란? (0) | 2025.08.16 |
| [JavaScript] 자바스크립트의 실행 컨텍스트란 무엇일까? (4) | 2025.08.14 |