JS 파일은 어떻게 실행될까? (with V8 engine)

2025. 1. 24. 10:33웹프로그래밍/JavaScript

 

JS, React로 프로그래밍을 하면서도, 정작 JS 파일이 어떻게 브라우저 엔진에서 처리되고 실행되는지에 대해 무지했었다.

<You don't know JS Yet> 책을 읽으면서 관련 내용을 간단히 정리해본다.

 

보통 프로그래밍 언어를 컴파일 언어와 인터프리터를 거치는 스크립트 언어로 구분할 때,

JS는 일반적으로 스크립트 언어로 분류된다.

그런데 과연 JS가 마냥 한줄씩 처리되는 인터프리터 언어로 작동할까?

자바스크립트를 사용해본 개발자라면, 그렇지 않을 것이라 짐작할 수 있을 것이다.


 

실제로 JS는 실행 전 별도의 단계에서 파싱과 컴파일이 일어난다.

개발자가 지정한 변수/함수/블록의 위치는 파싱/컴파일 단계에서 스코프 규칙에 따라 분석되고,

그 결과에 따라 결정된 스코프 구조는 대개 런타임에 영향을 받지 않는다.

(비엄격모드에서 eval, with 등 키워드를 통해 런타임에 코드가 결정되지 않는다면...)

 

따라서, JS를 단순히 인터프리터 언어라고 말할 수는 없다.

<You don't know JS Yet>의 저자는 오히려 JS는 컴파일 언어라고 보는게 맞다고 주장한다.

 

책에서 설명하는 작성된 JS의 실행 과정은 아래와 같다.

1. Babel 등으로 트랜스파일을 한다 : 이전 ECMA 버전 기준으로 구동되는 브라우저에서도 정상적으로 작동하게 하기 위해서

2. WebPack과 같은 번들러를 거쳐 번들링되고, 그 결과가 JS 엔진에 전달된다.

3. JS 엔진은 전달받은 코드를 토크나이징/렉싱 및 파싱하여 추상 구문 트리 (Abstract Syntax Tree, AST)로 변환한다.

  • 토크나이징/렉싱: 문자열을 토큰이라 불리는 의미 있는 조각으로 쪼갠다. ex) let a = 3; => let, a, =, 3, ;
  • 파싱: 토큰 배열을 프로그램 문법 구조를 반영하는 추상 구문 트리(AST)로 변환한다.

4. JS 엔진은 AST를 이진 바이트 코드로 변환한다.

이 과정에서 JIT(Just-In-Time) Compiler가 작동하며, 최적화가 함께 진행된다.

5. JS 가상 머신이 프로그램을 실행한다.


V8 엔진은 어떻게 작동할까?

 

V8 엔진은 C++로 작성된, ECMAScript(JS)와 WebAssembly를 처리할 수 있는 엔진이다.

실제 V8엔진에서 JS 소스를 통해 프로그램을 실행하는 과정은 아래 그림과 같다.

 

소스코드 - Parser - AST 까지의 동작은 위에서 설명된 내용과 유사한 것 같다.

 

V8에서는 Ignition을 이용하여 AST를 바이트 코드로 컴파일한다.

신기하게도, 변환된 바이트코드는 Ignition Bytecode Interpreter에서 인터프리터 방식으로 실행될 수도 있고,

TurboFan JIT compiler를 거쳐 네이티브 코드로 최적화되어 실행될 수도 있다.

 

Ignition 인터프리터로 실행한다면 초기에 빠르게 실행할 수 있고,

TurboFan JIT 컴파일러를 통해 실행된다면 실행 시 성능이 최적화될 수 있다.

 

따라서 이 두가지 방식의 장점을 융합하여, V8은 인터프리터 + JIT 컴파일러 하이브리드 모델을 사용한다고 한다.

V8의 프로파일링 시스템이 자주 실행되는 코드를 탐지하여 해당 부분은 JIT 컴파일러를 통해 컴파일한다.

또한 TurboFan에서는 히든클래스, 인라인캐싱의 방법을 이용하여 최적화를 한다고 한다...

 

 

 

이 분야는 깊게 파려면 끝이 없는 것 같고, 관련 지식이 많은 것도 아니라 V8엔진 링크를 남기고 글을 마무리하려 한다.

https://v8.dev/

'웹프로그래밍 > JavaScript' 카테고리의 다른 글

모듈 패턴  (0) 2025.03.30
클로저  (0) 2025.01.26
스코프와 호이스팅  (0) 2025.01.26