Javascript 동작 원리 (1)

Roy Jung·2023년 7월 18일
0
post-thumbnail
post-custom-banner

Javascript Engine

자바스크립트 엔진의 대표적인 예는 Google V8 엔진이다. Chrome 브라우저, NodeJS 런타임 등에서 사용되고 있다. V8 은 Chrome과 Node.js에서 사용합니다. 아래는 엔진의 구조도를 간단히 나타낸 그림입니다.

1) Memory Heap : 메모리 할당이 일어나는 곳(객체, 배열, 함수 등)
2) Call Stack : 코드 실행에 따라 호출 스택이 쌓이는 곳

호출 스택(Call Stack)

자바스크립트는 기본적으로 싱글 쓰레드 기반 언어입니다. 호출 스택이 하나라는 소리죠. 따라서 한 번에 한 작업만 처리할 수 있습니다.

호출 스택은 기본적으로 우리가 프로그램 상에서 어디에 있는지를 기록하는 자료구조입니다. 만약 함수를 실행하면(실행 커서가 함수 안에 있으면), 해당 함수는 호출 스택의 가장 상단에 위치하는 거죠. 함수의 실행이 끝날 때(리턴 값을 돌려줄 때), 해당 함수를 호출 스택에서 제거합니다. 그게 스택의 역할입니다.

아래 예제 코드를 살펴볼까요.

function multiply(x, y) {
    return x * y;
}
function printSquare(x) {
    var s = multiply(x, x);
    console.log(s);
}
printSquare(5);

처음 엔진이 이 코드를 실행하는 시점에는 호출 스택이 비어있습니다. 하지만 코드가 실행되면서 호출 스택은 아래와 같이 변합니다.

Javascript Runtime Environment

JavaScript는 싱글 스레드 언어다. 한 번에 하나의 작업만 실행할 수 있다. JavaScript로 30초가 걸리는 작업을 해야한다고 가정해보자. 이 작업을 시작하면 유저는 30초 동안 ui에서 할 수 있는 일이 없다. 단지 기다려야 할 뿐이다. 이를 블로킹이라고 한다.

하지만, 웹 어플리케이션에서는 동시에 다른 무언가를 할 수있다. 예를 들면, 브라우저에서는 파일을 다운로드 받고 있으면서 다른 링크로 이동한다던지, Node.js에서는 HTTP 요청을 처리하기도 한다. V8과 같은 JavaScript 엔진은 단일 호출 스택(Call Stack)을 사용하며, 요청이 들어올 때마다 해당 요청을 순차적으로 Call Stack에 담아 처리할 뿐이다.

JavaScript 언어 자체에는 Multi Threading을 할 수 없지만, JavaScript가 동작하고 있는 ’브라우저‘(브라우저라는 프로그램)에서는 여러 스레드를 활용할 수 있다. 브라우저에서 지원하는 Web API를 사용하는 것이다. Web API는 JavaScript엔진 자체가 제공하지 않는, 브라우저에서 제공하는 API다. DOM API, setTimeout, HTTP 요청 등이 여기에 포함된다. JavaScript Runtime Environment(브라우저 or Node.js)에는 Event Loop가 있다. 이 Event Loop를 통해 여러 처리를 동시에 할 수 있는 것이다. 브라우저 환경을 그림으로 표현하면 다음과 같다.

비동기 호출을 위해 사용하는 setTimeout, fetch 같은 함수는 자바스크립트 엔진이 아니라 Web APIs 영역에 따로 정의 되어 있다. 또한 Event Loop나 Task Queue 같은 장치도 자바스크립트 엔진 외부에 구현되어 있다. 아래 사진은 Node.js 환경이다.

이 그림에서도 브라우저 환경과 비슷하다. Node.js는 비동기 IO를 지원하기 위해 libuv 라이브러리를 사용하고, libuv에서 Event Loop를 제공한다. 자바스크립트 엔진은 비동기 작업을 위해 Node.js API를 호출하고, 이때 넘겨진 콜백은 libuv의 Event Loop를 통해 스케줄되고 실행된다.

확실한 것은, 자바스크립트가 ‘단일 스레드’ 기반의 언어라는 것은, ‘자바스크립트 엔진이 단일 Call Stack을 사용한다’는 관점에서만 사실이다. 실제 자바스크립트가 실행되는 환경(브라우저, Node.js)에서는 주로 여러 개의 스레드가 사용되고, 이런 구동 환경이 Call Stack을 사용하는 자바스크립트 엔진과 상호 연동하기 위해 사용하는 장치가 ‘이벤트 루프’인 것이다. 즉, 브라우저, Node.js환경은 자바스크립트 엔진의 Wrapper 역할을 하고 있다.

비동기 코드(non blocking)는 코드의 실행이 완료되지 않아도 다음 코드를 실행하는 것을 말한다. Event loop이 있어 javascript 자체는 싱글스레드임에도 불구하고 비동기 코드를 다룰 수 있고 multi threads처럼 보일 수 있다.

다음 글에서 Event loop과 관련해서 코드 실행 순서에 대해 자세히 알아보자

profile
내가 보려고 쓰는 글
post-custom-banner

1개의 댓글

comment-user-thumbnail
2023년 7월 18일

소중한 정보 잘 봤습니다!

답글 달기