이번엔 기본적인 자바스크립트의 작동원리를 다시 공부하는 차원에서 포스팅하고자 함.
자바스크립트는 싱글 스레드로 동작하는 언어이다.
이 말은 한번에 하나의 작업만 수행될 수 있다는 뜻인데,
우리는 자바스크립트와 관련하여 비동기, 동시성, Non Blocking 등의 키워드들을 본 적이 있다.
?? 싱글 스레드인데 어떻게 동시성이 가능한 걸까? 🤔
자바스크립트 코드를 해석하고 실행하는 자바스크립트 엔진. ( = 인터프리터 )
아래의 그림이 자바스크립트 엔진을 나타내고 있다.
자바스크립트 엔진은 메모리 힙 + 콜 스택 으로 구성되어 있다.
여기서 콜 스택이 1개인 것은 자바스크립트가 싱글 스레드라는 점이기 때문이다.
자바스크립트 엔진을 구동하는 런타임 환경이 담당? Yes
동시성을 보장하는 비동기, 논블로킹 작업들은 브라우저 혹은 Node.js 같은 자바스크립트 엔진을 구동하는 환경에서 담당해준다.
아래 그림이 바로 자바스크립트 엔진과 외부의 런타임 환경들이 조합된 모습이다.
여기서 우리가 들어봤던 Web API, Task Queue, Event Loop 들을 볼 수 있다.
Web API :
브라우저에서 자체 지원하는 api.
DOM, ajax, setTimeout 등의 비동기 작업들을 수행할 수 있도록 api를 지원한다.
태스크 큐 :
Web API에서 비동기 작업들이 완료되고 호출된 콜백 함수들이 대기하는 공간.
FIFO 방식을 따른다.
이벤트 루프 :
웹 브라우저와 Node.js에서 싱글 스레드인 자바스크립트를 비동기 처리 동작을 하도록 하는 핵심 요소.
콜 스택과 태스크 큐를 수시로 확인하며 콜 스택이 비었을 시 태스크 큐에 있는 작업들을 콜 스택으로 넘겨준다.
자바스크립트는 싱글 스레드이지만 이러한 Web API, Task Queue, Event Loop 덕분에 멀티 스레드처럼 보여지는 것이다.
예시 코드를 들어보자.
console.log('1');
setTimeout(() => console.log('2'), 1000);
console.log('3');
이 코드의 출력 순서는 어떻게 될까?
1
3
2
setTimeout의 작업은 태스크 큐로 옮겨졌다가 콜스택이 비었을 때 마지막으로 실행된다. 따라서 2가 마지막으로 출력된다.
그러면 setTimeout의 시간을 0초로 두면 어떤 결과가 나올까?
console.log('1');
setTimeout(() => console.log('2'), 0);
console.log('3');
1
3
2
결과는 전과 똑같다. 시간을 중요하지 않다.
setTimeout은 Web API에서 지원되는 비동기 함수이므로 자바스크립트 엔진은 Web API에 setTimeout을 요청한다.
콜스택에서는 Web API 요청 이후, setTimeout 함수가 종료되기 때문에 setTimeout은 제거된다.
Web API는 요청받은 setTimeout을 완료하고, 전달받은 Callback을 태스크 큐에 넘겨준다.
자바스크립트의 콜스택이 비게 되면 콜스택으로 옮겨져 실행된다.
시간이 0초라고 콜스택에 바로 쌓이는 다른함수들보다 빨리 호출되는 것이 아니다.
http://latentflip.com/loupe 🌟
이 링크에서 자바스크립트 코드가 어떻게 동작하는지 확인할 수 있다.
정리
가정 : Web API에서 지원하는 비동기 작업 코드가 실행되었을 때
만약 http 요청의 작업을 동기로 수행했다면 해당 함수가 콜스택에 쌓인채로 머물것이고, 자바스크립트 엔진은 해당 작업이 끝날때까지 어떠한 작업도 수행할 수 없다.
그러나 Javascript는 비동기 작업들을 Web api에게 넘겨줌으로써, 해당 작업이 완료될때까지 다른 코드들을 실행할 수 있다. 이것이 바로 논블로킹.