Javascript를 해석하는 Javascript engine과 web browser에 화면을 그리는 rendering engine은 다른 것이다. 브라우저에서는 V8 엔진, 서버에서는 node.js가 있다.
V8엔진에서는 Call stack, Task Queue, Heap으로 나뉘고 Event loop라는 것이 Task(Callback) Queue에 들어가는 task들을 관리하게 된다.
자바스크립트 엔진과 그 실행 환경을 상호 연동시켜주는 장치가 바로 event loop다. 따라서, 이벤트 루프는 자바스크립트 엔진에 있지 않고 그 환경에 속한다.
function foo(b) {
var a = 10;
return a + b;
}
function bar(x) {
var y = 2;
return foo(x + y);
}
console.log(bar(1));
bar
함수 호출. bar
에 해당하는 stack frame 형성. y
local variable 생성.bar
함수는 foo
함수 호출. bar
함수는 종료되지 않아서 pop이 안된다.foo
함수가 call stack에 push.foo
함수에서는 a+b
라는 값을 return 하면서 함수가 끝나고, stack에서 pop된다.bar
함수로 돌아와서 foo
함수로부터 받은 값을 return 하면서 bar
함수도 끝나고 pop된다.동적으로 생성된 객체는 heap에 할당
setTimeout(function() {
console.log('first');
}, 0);
console.log('second');
// 콘솔:
// second
// first
Javascript에서 비동기로 호풀되는 함수들은 call stack에 쌓이지 않고 task queue에 enqueue된다. Javascript에서는 event에 의해 실행되는 함수들이 비동기로 실행된다.
자바스크립트의 실행 환경은 2가지 큐를 가지고 있으며 각각 스크립트 실행, 이벤트 핸들러, 콜백함수 등의 task가 담기는 공간이다. Task가 콜백함수라면 그 종류에 따라 다른 큐에 담기며 대표적인 예로는 다음과 같은 것들이 있다.
Event loop는 2개의 queue를 감시하고 있다가 call stack이 비게 되면, 콜백함수를 꺼내와서 실행한다. 이 때 microtask queue의 콜백함수가 우선순위를 가진다.
Microtask queue의 콜백함수를 전부 실행하고 나서 task queue의 콜백함수들을 실행한다. (UI 렌더링이 task queue에 속하기 때문에 microtask queue의 task가 많으면 rendering이 지연될 수 있다.)
console.log('call stack');
setTimeout(() => console.log('task queue!'), 0);
Promise.resolve().then(() => console.log('microtask queue'));
//콘솔:
// call stack
// microtask queue
// task queue