JavaScript 코드를 실행하는 프로그램 또는 인터프리터
자바스크립트 엔진의 대표적인 예는 Google V8 엔진이다. V8은 Chrome과 Node.js에서 사용한다.
ECMAScript(이크마스크립트)는 자바스크립트(JavaScript)의 표준 규격을 정의하는 스크립트 언어 표준.
엔진의 주요 두 구성요소는 메모리 힙과 호출 스택이다.
Js는 기본적으로 Single Thread 기반 언어이다. 호출 스택이 하나라는 소리이다.
따라서 한 번에 한 작업만 처리할 수 있다.
함수에 들어가면 스택 맨 위에 PUSH. 함수에서 반환하면 스택의 맨 위에서 POP된다. 이것이 스택이 할 수 있는 전부이다.
function multiply(x, y) {
return x * y;
}
function printSquare(x) {
var s = multiply(x, x);
console.log(s);
}
printSquare(5);
처음 엔진이 이 코드를 실행하는 시점엔 호출 스택이 비어있지만 코드가 실행되면서 호출 스택은 아래와 같이 변한다.
호출 스택의 각 단계를 스택 프레임(Stack Frame)이라고 한다.
예외(Exception)가 발생했을 때, 콘솔 로그 상에서 나타나는 스택 트레이스(Stack Trace) 는 해당 예외가 발생한 지점에서부터 예외가 처리될 때까지의 호출 스택의 상태를 보여주는 것이다.
function foo() {
throw new Error('SessionStack will help you resolve crashes :)');
}
function bar() {
foo();
}
function start() {
bar();
}
start();
"Blowing the stack" — 최대 호출 스택 크기에 도달했을 때 발생한다. 특히 재귀 반복문 코드를 광범위하게 테스트하지 않고 실행했을 때 자주 발생한다.
function foo() {
foo();
}
foo();
특정 시점에 함수 호출 횟수가 호출 스택(Call Stack)의 최대 허용치를 넘게 되면 브라우저가 이런 에러를 발생시킨다.
컴퓨터 프로그램이 실행되는 동안에 실제로 동작하는 환경을 의미.
컴퓨터 언어로 작성된 프로그램은 실행되기 전에 기계어로 변환되어야 하며, 이 변환은 컴파일러나 인터프리터에 의해 수행된다. 런타임은 이러한 변환 이후 프로그램이 동작하는 동안의 환경과 동작을 관리한다.
자바스크립트 엔진은 한 번에 단 한 가지의 일만 수행 가능한 싱글 스레드(Single thread) 방식으로 동작한다는 것은 알겠다! 그렇다면 setTimeout과 같은 비동기 함수들은 어떻게 논블로킹 방식으로 처리되는 걸까? 이 또한 프로그램이 멈추게 하는 요소였을텐데 말이다.
이런 자바스크립트 엔진에 동시성(Concurrency)을 지원하기 위해 웹 브라우저는 이벤트 루프(Event Loop)라는 것을 지원한다.
비동기 작업을 위해 사용했던 setTimeout
과 setInterval
함수는 ECMA Script의 기본 사양이 아닌 웹 브라우저에서 별도로 제공하는 Web API이다.
물론 기본적으로 소스 평가 과정을 거쳐 실행 컨텍스트로 올라가는 것은 동일하지만, 비동기 동작을 위한 타이머 정보(호출 시간, 콜백 함수)는 웹 브라우저나 Node.js와 같은 자바스크립트 런타임 환경에 의해 관리됨.
const foo = () => console.log("First");
const bar = () => setTimeout(() => console.log("Second"), 500);
const baz = () => console.log("Third");
bar();
foo();
baz();
// First
// Third
// Second
bar
함수 호출, bar
함수는 setTimeout
함수를 반환한다.setTimeout
에 전달한 콜백은 Web API에 추가되고, setTimeout
함수와 bar
는 호출 스택에서 제거됨.foo
가 호출되고 "First"
를 log
한다. foo
는 (undefined)
를 반환하고, baz
가 호출되며 콜백이 Queue에 추가된다.baz
는 "Third"
를 log
한다. 이벤트 루프는 baz
가 반환된 후 호출 스택이 비어있다고 판단하여 콜백을 Call stack에 추가한다."Second"
를 log
한다.이벤트 루프는 대기 중인 모든 콜백을 실행한다. 대기 중인 콜백들은 마이크로 태스크(Micro-tasks)와 매크로 태스크(Macro-tasks)로 큐에 분류된다.
이벤트 루프는 호출 스택(Call Stack)과 태스크 큐를 계속 지켜 보면서, 호출 스택이 비어있을 때 태스크 큐에 등록된 콜백 함수들을 호출 스택에 순차적으로 옮긴다. 만약 마이크로 태스크 큐에 콜백 함수가 있다면, 태스크 큐보다 우선적으로 참조한다.
이처럼 태스크 큐와 이벤트 루프를 갖고 있는 웹 브라우저와 자바스크립트 엔진의 협업에 의해 우리는 자바스크립트에서도 비동기 함수를 사용할 수 있는 것!!
실행 컨텍스트에 대해 좀더 깊게 공부 해보겠다.