현재 번역은 완벽하지 않습니다. 한국어로 문서 번역에 동참해주세요.
자바스크립트는 "이벤트 루프"에 기반한 병행성(concurrency) 모델을 가지고 있습니다. 이 모델은 C 또는 Java와 같은 언어와 완전히 다릅니다.
런타임 개념
이어지는 섹션에서는 이론적 모델을 설명합니다. 모던 자바스크립트 엔진들은 아래 묘사된 개념들을 구현하고 최적화 합니다.
시각적 표현
스택
함수 호출은 프레임들의 스택을 형성합니다.
function f(b){ var a = 12; return a+b+35; } function g(x){ var m = 4; return f(m*x); } g(21);
g를 호출할 때
, g
arguments와 로컬 변수를 포함하는 첫번째 프레임이 생성 됩니다. g가 f를 호출하면 f arguments와 로컬 변수를 포함한 두번 째 프레임이 생성되어 첫번째 프레임 위에 추가 됩니다. f가 반환할 때 최상위에 있던 두번째 프레임은 스택에서 빠져나옵니다. (g호출 프레임만을 남겨둔 채). g가 반환하면, 스택은 비워집니다.
힙
객체들은 힙 안에 위치 됩니다. 힙은 메모리의 넓은 비구조화 영역을 지칭합니다.
큐
자바스크립트 런타임은 메시지 큐를 가지고 있습니다. 이 큐는 처리될 메시지들의 리스트 입니다. 각 메시지에는 함수가 연관 되어 있습니다. 스택이 비어 있으면 큐에서 하나의 메시지가 꺼내지고 처리 됩니다. 이 처리는 연관된 함수를 호출하는 것으로 구성됩니다 (결과적으로 초기 스택 프레임을 생성합니다). 메시지 처리는 스택이 다시 비워질 때 종료 됩니다.
이벤트 루프
이벤트 루프는 그 구현 방식 때문에 붙은 이름이며 보통 다음과 유사합니다 :
while(queue.waitForMessage()){ queue.processNextMessage(); }
queue.waitForMessage
함수는 현재 아무 메시지도 없다면 새로운 메시지 도착을 동기적으로 기다립니다.
"Run-to-completion"
각각의 메시지는 다른 어떤 메시지가 처리 되기 전에 완전히 처리 됩니다. 이것은 당신의 프로그램을 살펴볼 때, 함수가 실행 될 때마다 그것은 미리 비워질 수 없고 어떤 다른 코드 실행에 앞서 완전히 실행 된다는 (그리고 그 함수가 다루는 데이터가 변경 될 수 있다는) 사실을 포함해 뛰어난 특징을 제공합니다. 이것은 C언어와 다릅니다. 예를 들어 C에서는 함수가 하나의 쓰레드에서 실행 될 때 그것은 어떤 시점에 다른 쓰레드에 있는 어떤 코드를 실행하기 위해 멈출 수 있습니다.
이 모델의 부정적인 면은 어떤 메시지가 완료되기 까지 지나치게 오래 걸린다면 웹 어플리케이션은 클릭이나 스크롤과 같은 사용자 인터랙션을 처리할 수 없게 됩니다. 브라우저는 이러한 상황을 "a script is taking too long to run"과 같은 대화상자로 완화 합니다. 추천되는 좋은 방법은 메시지 처리를 짧도록 만드는 것과 하나의 메시지를 여러개의 메시지로 나누는 것 입니다.
메시지 추가하기
웹브라우저에서는 이벤트가 발생하고 그에 해당하는 이벤트 리스너가 있을 때 언제든 메시지가 추가 됩니다. 아무런 리스너가 없다면 그 이벤트는 버려집니다. 클릭 이벤트 핸들러가 있는 요소에 대한 클릭은 메시지를 추가 합니다.
setTimeout
에 대한 호출은 주어진 두번째 인자의 시간 후에 메시지를 큐에 추가합니다. 큐에 아무런 메시지가 없다면 그 메시지는 즉시 실행 됩니다. 그러나 메시지들이 있다면 setTimeout
메시지는 다른 메시지들이 처리될 때까지 기다려야 합니다. 그렇기 때문에 두번째 인자는 보장된 실행 시간이 아닌 최소한의 실행 시작 시간을 나타냅니다.
Zero delays
Zero delay는 사실 0ms 후에 즉시 실행되는 콜백을 의미하지 않습니다. 0ms과 함께 setTimeout
를 호출하는 것은 주어진 시간 후에 콜백을 실행하지 않습니다. 실행은 큐에 대기중인 작업들에 달렸습니다. 아래 예제에서 ''this is just a message'' 라는 메시지는 콜백 안에 있는 메시지가 처리 되기 전에 화면에 나타날 것입니다. 왜냐하면 지연(delay)은 보장된 시간이 아니라 요청을 처리하기 위해 필요한 최소의 시간이기 때문입니다.
(function () { console.log('this is the start'); setTimeout(function cb() { console.log('this is a msg from call back'); }); console.log('this is just a message'); setTimeout(function cb1() { console.log('this is a msg from call back1'); }, 0); console.log('this is the end'); })();
몇가지 런타임 통신
웹워커 또는 크로스 오리진 아이프레임은 자신의 스택, 힙, 메시지 큐를 가지고 있습니다. 두 별개의 런타임들은 postMessage
method를 통해서만 서로 통신할 수 있습니다. 이 메서드는 다른 런타임이 message
이벤트 핸들러를 등록하고 있다면 해당 런타임의 큐에 메시지를 추가합니다.
Never blocking
이벤트 루프 모델의 무척 재밌는 부분은 다른 언어와 달리 자바스크립트는 결코 Block하지 않는다는 것입니다. I/O 처리는 흔히 이벤트와 콜백으로 처리 됩니다. 그래서 응용프로그램이 IndexedDB query 반환을 기다리고 있거나 XHR 요청 반환을 기다릴 때에도 여전히 사용자 입력과 같은 다른 것을을 처리할 수 있습니다.
alert
또는 synchronous XHR과 같은 구현 예외가 존재 합니다. 그러나 그것들은 사용되지 않는 것이 좋다라고 여겨집니다. 예외를 위한 예외를 조심하세요 (그러나 보통 구현 버그일뿐 그이상 아무것도 아닙니다).