JavaScript Engine

자바스크립트 엔진이란 자바스크립트 코드를 실행시키는 프로그램이다.

모든 브라우저에는 자체 자바스크립트 엔진이 있다. 그중에서도 가장 잘알려진 엔진인 구글의 V8 엔진이다.
V8은 구글크롬을 구동시키고 서버측 애플리케이션을 구축하는데 사용가능한 Node.js 런타임을 구동시킬 수 있다. V8은 외부 브라우저에서도 nodejs를 구동시킬 수 있다.

물론 다른 브라우저들에도 자체 자바스크립트 엔진이 있다.

JavaScript Engine 의 구성요소

콜스텍

우리가 실행할 코드가 쌓이는 곳이며 실행할 코드는 실행 콘텍스트라도 불린다.

모든 객체들이 저장되어있는 장소이며 객체들이 메모리에 들어가 있다.

그러면 콜스텍에 쌓여있는 실행 컨텍스트는 어떻게 컴파일이 될까?

컴파일

전체 코드는 한번에 기계어로 변환되고 (기계어로 변환된 코드는 Portable file에 저장된다.) 여기서 컴퓨터가 읽을 수 있는 바이너리 코드로 쓰여진다. 이때 기계어로 변환되는 과정이 컴파일이다. 기계어로 변환된 코드를 (컴파일된 코드) 바이너리 코드다시 써서 컴퓨터가 실행시킬수 있다.

인터프리터

인터프리터는 소스코드를 한줄 한줄 읽어서 바로 컴퓨터가 실행시킬수 있게한다. 물론 기계어로 변환하는 과정이 필요하지만 실행직전에 해당 과정이 이루어진다. 하지만 이과정은 느리다. 자바스크립트가 이러한 언어라고 하지만 더이상은 아니다. 이제 자바스크립트는 Just In Time 컴파일 코드라고 한다.

Just-In-Time 컴파일


이과정은 한번에 기계어로 변환한다음 즉시 실행합니다. 이 기계에는 Portable file에 저장되지 않고 즉시 프로그램이 실행됩니다.

  1. 자바스크립트 코드가 엔진에 들어가면 Paring 과정을 거치게된다. 코드를 읽는 것이다. 코드가 Paring되어 구문 별로 분석이되고 이렇게 분석이된 파일은 데이터 구조로 편성이된다. 이러한 구조를 AST (Abstract Syntax Tree - 추상 구문 트리)라고 합니다..

먼저 각 코드줄을 분할 해서 언어에 의미 있는 조각으로 나눈다. const, function등으로 이렇게 구조화되어 나뉜것을 트리에 저장한다. 여기서 Syntax Error가 있는지도 확인합니다.

  1. 이렇게 생성된 AST는 기계어 코드로 컴파일 된다.
    이러한 기계어 코드는 즉시 실행이되는데 실행이 될때에는 자바스크립트 엔진의 Call Stack 에서 실행컨텍스트 단위로 이루어집니다.
  1. 이제 이미 실행중인 프로그램 실행중에 다시 이 기계어들이 최적화 과정을 거치고 컴파일되어 최적화된 코드로 다시 실행된다. 그리고 이러한 모든 파싱 및 컴파일 최적화들은 코드에서 접근할 수 없는 자바스크립트엔진의 일부 스레드에서 이루어집니다.

이러한 과정은 메인 스레드에서 완전히 분리가 되어서 기본적으로 Call Stack으로 실행이됩니다.

JavaScript Runtime 의 브라우저 동작


  • 자바스크립트 런타임은 브라우저안에서 자바스크립트가 동작하기 위한 모든 것을 포함한 거대한 통이라고 보자면
    런타임동안 항상 자바스크립트 엔진이 구동되고 있습니다. 자바스크립트 엔진이 없으면 런타임이 구동되지않고 런타임동안에는 자바스크립트 엔진이 항상 구동되고 있습니다. 하지만 런타임안에는 다른 요소들도 있습니다.

  • Web API 라고 하는 것들인데 이러한 것들은 DOM 객체와 다른 여러 기능들을 지원합니다. (Console, Timers ... )

  • CallBack Queue 라고 하는 것들도 런타임안에 포함됩니다. DOM요소에 이벤트 핸들러에대한 CallBack 함수등이 이러한 콜백 큐에 저장이 됩니다.
    예를 들자면, 어떤 요소에 클릭 이벤트 핸들러가 있어 클릭이벤트가 발생하면 해당하는 콜백함수가 콜백 큐에 저장이되어 있다가 자바스크립트 엔진의 CallStack이 비어버리면 콜백함수가 스택에 전달이 되어 실행되게 됩니다. 이러한 것은 이벤트 루프라고 불리는 것에 의해서 발생합니다. 이벤트 루프는 콜백 큐에서 콜백함수를 CallStack에 넣어 실행될 수 있게 합니다. 이렇게 이벤트 루프가 CallBack Queue에서 하나씩 콜백함수를 CallStack에 옮겨 실행컨텍스트를 생성할때마다 이벤트 루프틱이 발생했다고 합니다.

이벤트 루프는 자바스크립트의 nonblocking concurreny model (비차단 동시성 모델)을 구현합니다.

자바스크립트는 단일 스레드 프로그램입니다. 하나의 주 스레드에서 하나의 코드가 모두 실행될 때까지 다른 나머지 코드들은 실행이 차단됩니다. 하지만 자바스크립트는 이러한 차단성을 갖지 않습니다. 위의 이벤트루프와 WebAPI를 이용한 비동기 방식으로 비차단 동시성 모델을 구현합니다.

MicroTask Queue


Promise 객체의 콜백함수는 CallBack Queue가 아닌 특별한 Queue에서 실행됩니다. 바로 MicroTask Queue 입니다. 하는일은 CallBack Queue 랑 비슷합니다. 이 특별한 Queue에서 실행되는 콜백함수는 observer 콜백함수도 실행됩니다.

  • 기본적으로 CallBack Queue보다 우선순위가 높습니다. 즉, CallBack Queue에 대기중인 콜백보다 MicroTasks Queue에 대기중인 Promise 콜백들이 더 먼저 실행되고 MicroTasks Queue에 대기중인 Promise 콜백이 없으면 CallBack Queue에서 이벤트 루프틱이 일어납니다.

🙋‍♂️ 여기서 끊임없이 Promise 콜백들이 늘어난다면 CallBack Queue가 실행되지 않을수 있을까?

  • 대한 답변은 놀랍게도 그렇다. 하지만 일반적으로 위 문제는 별로 문제가 되지 않는다. 이러한 상황에서는 성능상 문제가 발생한다. 따라서 microTask Queue를 사용하는데 주의를 기울여야 한다.

JavaScript Runtime의 브라우저 외부 동작

브라우저 외부의 동작이므로 WebAPI를 사용할 수 없고 다른 기능들이 들어간 채 비슷한 구조로 런타임이 구동됩니다.

profile
일상을 기록하는 삶을 사는 개발자 ✒️ #front_end 💻

0개의 댓글