자바 스크립트는 싱글 스레드 언어로 한 번에 하나의 함수만 처리할 수 있는데, 마치 멀티 스레드 언어 같이 여러 작업들은 동시 실행하고 있다. 어떻게 자바스크립트에서는 여러 작업을 진행하는지 정리해보았다.

한 번에 하나의 작업만 순차적으로 처리하는 방식, 즉 한 번에 하나의 작업을 처리할 수 있는 단일 콜 스택을 가진다.
1️⃣-2️⃣ 싱글 스레드 한계
병목 현상 - 프로그램의 순차적 실행 부분이 전체 성능을 제한한다.
블로킹 이슈 - 단일 스레드가 I/O 대기나 긴 계산 작업에 갇히면 전체 시스템이 정지한다.
하드웨어 활용도 저하 - 2025년 기준, 대부분의 CPU가 8~32코어 구성을 가지고 있지만, 단일 스레드는 1코어만 활용하여 나머지 코어에 대한 활용이 진행되지 않는다.
2️⃣-1️⃣ Web API & 이벤트 루프
비동기 작업이 발생하면, 해당 비동기 작업은 브라우저의 web API에서 담당하게 된다. setTimeout, fetch 등 과 같은 작업은 Web API에서 진행하고 자바스크립트 엔진에서는 다른 코드의 실행을 진행한다. Web API에서 비동기 작업이 완료되면 그 작업은 태스크 큐에 들어가 대기한다. 이 후 대기하고 있는 작업은 이벤트 루프에 의해서 처리된다.
2️⃣-2️⃣ 이벤트 루프 작동 원리
콜 스택 확인하고 테스크 큐에서 대기 중인 작업을 콜 스텍으로 이동 및 실행시킨다. 이렇게 자바 스크립트는 싱글 스레드임에도 비동기적 작업이 가능하다. 이때 주의할 점은 마이크로태스크 큐가 태스크 큐보다 우선 처리된다는 것이다.
2️⃣-3️⃣ 마이크로태스크 큐 & 태스크 큐
자바스크립트의 이벤트 루프에서 마이크로태스크 큐와 태스크 큐는 비동기 작업을 처리하는 두 가지 다른 큐이다.
태스크 큐
태스크 큐는 일반적인 비동기 작업을 처리하는 큐이다. 각 반복마다 하나의 태스크만 처리하고 브라우저 렌더링이 매크로태스크 사이에 일어날 수 있다는 특징이 있다.
setTimeout, setInterval, 이벤트 핸들러 작업, I/O 작업, UI 렌더링 등이 있다.
마이크로태스크 큐
마이크로태스크 큐는 더 높은 우선순위를 가진 작업을 처리하는 큐이다, 현재 실행 중인 스크립트 직후에 실행되며 큐가 비워질 때까지 계속해서 처리된다. 만일 새로운 마이크로태스크가 생기면 즉시 큐에 추가되어 우선 처리된다.
Promise의 then, catch, finally, MutationObserver등의 비동기 콜백이 포함된다.
3️⃣-1️⃣ Promise 체이닝 (.then, .catch, .finally)
프로미스는 비동기 작업의 최종 완료 또는 실패를 나타내는 객체이다. 프로미스 체이닝은 메서드 체이닝 방식을 사용하며 catch 블록을 통해 에러를 처리한다.
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error))
.finally(() => console.log('Operation completed'));
3️⃣-2️⃣ async/await
async/await는 동기 코드와 더 유사한 구조를 가지며 에러는 try-catch 블록을 통해서 진행된다.
await 키워드는 프로미스가 처리될 때까지 함수 실행을 일시 중단하지만, 메인 스레드는 차단하는 것은 아니다.
async function loadData() {
const response = await fetch(url);
const data = await response.json();
return data;
}
3️⃣-3️⃣ 웹 워커(Web Workers)
웹 워커는 메인 스레드와는 별도로 백그라운드에서 스크립트를 실행할 수 있게 해주는 기술이다. 이를 통해 CPU 집약적인 작업을 별도의 스레드에서 실행할 수 있게 된다.