JavaScript는 Single Thread Language 이다.
자바스크립트의 콜 스택은 한 개이기 때문에 다른 작업이 추가로 들어왔을 때, 다른 작업 콜 스택에서 작업을 하는 것이 아니라 현재 콜 스택의 위에 쌓이게 된다. 따라서 자바스크립트는 한 번에 한 개의 작업만 수행할 수 있다.
그렇기 때문에 자바스크립트는 동기(Synchronous)적 특성을 가질 수 밖에 없다. 동기적 이게 되면 작업의 시간이 길어지면 길수록 자원 낭비가 심해진다.
다행히도 이를 해결할 방법은 존재하는데, 비동기(Asynchronous)적 방식으로 시간이 오래 걸리는 작업은 브라우저의 화면에서 돌아가도록 처리하고, 당장 빠르게 해결할 수 있는 일은 콜 스택에서 수행하는 방식이다. 이러한 작업이 수행이 가능한 이유는 자바스크립트가 구동될 때 자바스크립트 엔진뿐만 아니라, 자바스크립트 런타임(JavaScript Runtime)이라는 더 큰 범위의 동작 원리가 존재하기 때문이다.
모든 브라우저는 자바스크립트 엔진뿐 아니라 web API도 함께 제공되는 자바스크립트의 런타임을 내장하고 있다. web API는 여러가지 기능이 내장된 하나의 애플케이션이라고 볼 수 있다. web API를 통해 HTTP 요청을 보내거나, DOM에서 이벤트를 실행하거나, 실행을 연기하는 등의 작업이 가능하다.
크롬 개발자 모드의 콘솔에서 window
를 입력하면 브라우저에 내장된 자바스크립트 객체가 출력되는데, 이것이 바로 web API이다. 이렇게 web API를 이용하여 화면에서 비동기적으로 작업을 처리하고, 해당 작업을 마치면 콜 스택에 해당 작업이 끝났음을 알려줘서 그 작업을 수행할 수 있도록 한다.
콜 스택에 web API를 활용한 작업이 들어오면, 해당 작업은 그대로 web API에게 전달한다. 그러면 web API는 해당 작업을 처리하여 콜백 큐(Callback Queue)에게 전달한다.
이벤트 루프(Event Loop)는 끊임없이 콜 스택과 콜백 큐를 모니터링하고 있는 존재이다. 만약 콜스택이 비어있을 경우, 콜백 큐에 차곡차곡 쌓여있는 작업들은 콜 스택에게 전달하여 최종적으로 해당 작업이 처리하도록 하는 역할이다. 아무리 web API가 빠르게 일을 처리하여도, 콜 스택이 비어있지 않으면 이벤트 루프와 콜백 큐의 작업은 콜 스택에게 전달되지 않는다. 자바스크립트 런타임에 대한 이해를 통해 싱글 스레드 언어인 자바스크립트를 비동기적으로 이용할 수 있게 된다.
자바스크립트 런타임을 통해서 싱글 스레드 언어인 자바스크립트를 어떻게 비동기적으로 처리할 수 있는지 알았다. 하지만 이 모든 것들은 브라우저에 한정된 이야기, 즉 클라이언트 사이드 쪽에만 해당되는 이야기이다.
Node.js는 자바스크립트 런타임 중 하나로 브라우저 안에서만 놀던 자바스크립트를 브라우저 밖으로 꺼내온 장본인이다.
Node.js는 싱글 스레드로 구성되어 있으며, HTTP 요청이 들어오면 곧바로 LIBUV 비동기 런타임에게 전달한다. Node.js에 자세한 이야기는 다음번에 하도록 하겠다.
JavaScript 왜 싱글 스레드 일까?
비동기 작업의 원리(Web API, Task Queue, Event Loop)