자바스크립트는 싱글 스레드인데 어떻게 비동기 작업이 가능한가
August 30, 2022
자바스크립트는 싱글 스레드이지만 브라우저의 이벤트 루프와 WebAPIs 덕분에 비동기 작업이 가능하다
자바스크립트의 런타임은 한 번에 하나의 일만 할 수 있는 싱글 스레드가 맞다.
하지만 자바스크립트는 싱글 스레드인데 동시에 블로킹 없이 그 많은 작업을 처리할 수 있을까?
그 이유는 순수하게 자바스크립트만 실행시키는 경우는 많지 않고 브라우저와 함께 실행하기 때문이다. 프론트엔드의 경우, 자바스크립트 코드는 반드시 브라우저 를 통해 실행시키게 된다. 싱글 스레드인 자바스크립트가 브라우저와 만나면서, 비동기 작업이 가능해진다.
- 더 상세히 말하자면,
브라우저의이벤트루프를 통해 싱글 스레드인 자바스크립트가 비동기 작업을 할 수 있는 것이다. 그렇다. 비밀은이벤트 루프에 있다.
자바스크립트는 (브라우저 환경에서) 이벤트 루프에 기반한 동시성 모델 을 가지고 있다
이벤트루프는콜스택에서 setTimeout 같은 비동기 함수가 호출되면, 해당 작업을 브라우저에 내장된WebAPI에게 넘긴다. (setTimeout은 브라우저가 제공하는 WebAPI이며, 자바스크립트 고유 기능이 아니기 때문에 ECMAScript에는 존재하지 않는다)- 그리고
Web API안에서 타이머가 동작을 하거나 네트워크 통신을 진행하고, 코드가 실행될 준비가 되면태스크 큐에 해당 작업을 넣어준다. 콜 스택이 비었으면태스크 큐에서 대기 중인 함수를콜 스택으로 불러와 실행한다.
즉, 실제로 모든 함수가 순차적으로 싱글 스레드(콜 스택) 안에서 돌아가지만, 이런 시간 차가 너무 작기 때문에 비동기 작업이 여러 스레드에서 동시에 돌아갈 것이라고 착각하는 것이다.
- 참고로 브라우저 밖인 Node.js에서도 비동기 IO를 지원하기 위해
libuv라이브러리를 사용한다. 이libuv가 이벤트 루프를 제공하기 때문에, Node.js에서도 싱글 스레드인 자바스크립트가 비동기 작업을 할 수 있.
이벤트 루프의 작동원리 더 자세히 살펴보기

이벤트 루프는 콜 스택과 각 큐(마이크로태스크 큐, 애니메이션 프레임, 매크로태스크 큐)를 감시하고 있다가 콜 스택이 비었을 경우 정해진 우선순위에 따라 큐에서 하나씩 꺼내 콜 스택에 추가해주는 역할을 한다.
콜 스택의 작업을 모두 처리한다.- (마이크로태스크 큐)
콜 스택이 비었을 경우,마이크로태스트 큐를 확인하고 처리해야 할 작업이 있다면콜 스택에 넣고 처리한다. - (애니메이션 프레임) 만약
마이크로태스크 큐가 비었을 경우에는 애니메이션 프레임 를 확인하고 처리해야 할 작업이 있다면콜 스택에 넣고 처리한다. - (매크로태스크 큐) 상기 과정을 거치고 난 후 마지막으로
매크로태스크 큐를 확인하고 처리해야 할 작업이 있다면콜 스택에 넣고 처리한다.
즉, 마이크로태스크 큐 → 애니메이션 프레임 → 매크로태스크 큐 의 순서로 비동기 함수의 콜백 함수를 처리한다.
console.log("start")
Promise.resolve().then(() => {
console.log("Promise")
})
requestAnimationFrame(() => {
console.log("rAF")
})
setTimeout(() => {
console.log("Timeout")
}, 0)
console.log("end")
// 위 예제 실행시 로그 출력 결과는 start->end->promise->rAF->Timeout 이다.
// 실행할때마다 rAF와 Timeout의 순서가 바뀌긴 한다.관련 용어 정의
-
프로세스
- 컴퓨터에서
실행중인 프로그램을 의미한다. 프로그램이 실행되면 메모리에 올라가서 프로세스로서 동작한다.
- 컴퓨터에서
-
스레드
- 스레드는 프로세스 내에서 실행되는 작업흐름의 단위를 말한다. 보통 한 프로세스는 하나의 스레드를 갖고 있다. 프로세스의 환경에 따라 동시에 둘 이상의 스레드를 실행할 수 있으며, 이러한 방식을 멀티스레드라고 한다. 자바스크립트는 하나의 스레드만 갖고 있는
싱글 스레드이다.
- 스레드는 프로세스 내에서 실행되는 작업흐름의 단위를 말한다. 보통 한 프로세스는 하나의 스레드를 갖고 있다. 프로세스의 환경에 따라 동시에 둘 이상의 스레드를 실행할 수 있으며, 이러한 방식을 멀티스레드라고 한다. 자바스크립트는 하나의 스레드만 갖고 있는
-
동기(Synchronous)
동기는 데이터의 요청과 결과가 한 자리에서 동시에 일어나는 것을 말한다. 요청을 하면 시간이 얼마나 걸리던지 요청한 자리에서 결과가 주어져야 한다. 즉, 어떤 코드의 실행이 완료되어야 그 다음 줄의 코드로 넘어가 실행할 수 있는 것을 의미한다.
-
비동기(Asynchronous)
- 비동기는 동시에 일어나지 않는다는 의미이다. 비동기 프로그래밍은 프로그램의 주 실행 흐름을 멈추어서 기다리는 부분 없이 바로 다음 작업을 실행할 수 있게 하는 방식이다. 즉, 코드의 실행 결과를 별도의 공간에 맡겨둔 뒤 결과를 기다리지 않고 다음 코드를 실행하는
병렬처리방식이다.
- 비동기는 동시에 일어나지 않는다는 의미이다. 비동기 프로그래밍은 프로그램의 주 실행 흐름을 멈추어서 기다리는 부분 없이 바로 다음 작업을 실행할 수 있게 하는 방식이다. 즉, 코드의 실행 결과를 별도의 공간에 맡겨둔 뒤 결과를 기다리지 않고 다음 코드를 실행하는
-
Blocking
- 블로킹은 느리게 실행되는 코드다. 예를 들어, 네트워크 요청이나 이미지 프로세싱은 느리다. 느린 동작이 스택에 남아있는 것을 보통 블로킹이라고 말한다.
- 자바스크립트는 이렇게 느린 네트워크 요청을 하고는 다음 코드를 실행하기 위해 마냥 끝날 때까지 기다린다.
- 문제는 브라우저가 모든 리퀘스트가 완료될 때까지 멈춰있다는 것이다. 즉, 동기적으로 실행되는 네트워크 요청이 콜 스택을 블로킹하여 브라우저가 다른 일들을 하는 것을 막고 있다.이 때문에 렌더링이나 다른 코드를 실행하지 못하고 그냥 멈춰버린다.
- 이러한 블로킹 문제를 해결하기 위해 비동기 콜백을 사용한다.
-
콜 스택
- 콜 스택은 자바스크립트 코드가 실행되며 생성되는 실행 컨텍스트를 저장하는 자료구조이다. 또한 FILO(First In Last Out)으로 작동한다.
-
마이크로태스크 큐
Promise를 통한 비동기 요청 시의 콜백 함수는마이크로태스크 큐에 대기한다.- 마이크로태스크의 우선순위는 일반 태스크(매크로태스크)보다 더 높다.
-
애니메이션 프레임
requestAnimationFrame에 의해 등록되는 자료 구조로서requestAnimationFrame의 콜백 함수가 대기하는 자료구조이다.- 애니메이션 프레임의 우선순위는 마이크로태스크보다는 낮고, 매크로태스크 보다는 높다.
-
매크로태스크 큐
- 비동기 함수가 실행된 후 콜백 함수가 대기하는 자료구조이다.
- setTimeout(), setInterval()와 같은 태스크를 넘겨받는다.
-
Web APIs
- 브라우저에서 제공하는 별도의 API이다. DOM, SVG, Fetch, Canvas, setTimeout, Web share, push, notification 등은 모두 자바스크립트가 아닌 브라우저에서 제공하는 API이다.
- https://developer.mozilla.org/en-US/docs/Web/API