Event Loop란?
Event Loop(이벤트 루프)는 일반적인 프로그래밍 패턴 용어이며 완료된 Event(이벤트)를 반복해서 처리하는 간단한 루프이다.
Event란?
프로그램에 의해 감지되는 어떤 행동이나 발생된 사건을 말한다.
Ex) 마우스, 키보드를 누르는 등 사용자의해 발생하는 행위, 메모리가 소진되어 버리는 것같이 시스템에서 발생한 일들도 이벤트라고 한다.
이벤트가 발생할때 해당 이벤트를 처리하기 위한 이벤트 핸들러가 대기열(Queue)에 추가된다. 이벤트 루프는 대기중인 이벤트 핸들러를 지속적으로 감시하고 그에 따라 처리한다.
Browser, Node 환경의 차이
Browser(브라우저)는 샌드박스 환경이다.
샌드박스란?
보호된 영역 내에서 프로그램을 동작시키는 것으로, 외부 요인에 의해 악영향이 미치니는 것을 방지하는 보안 모델
이 모델에서 외부로부터 받은 프로그램을 보호된 영역, 즉 상자안에 가두고 나서 동작시킨다. 상자는 다른 파일이나 프로세스로부터는 격리되어 내부에서 외부를 조작하는 것은 금지되어 있다.
Node(노드)는 브라우저에서 수행하지 않는 특정 작업(파일 시스템, 네트워크 작업)을 추가로 해야한다.
브라우저, 노드 이벤트 차이
브라우저나 노드는 비동기 Event-driven 패턴을 사용한다.
브라우저의 Context(컨텍스트)에서 이벤트는 웹페이지 에서 사용자 상호 작용(예: 클릭, 마우스 이동, 키보드 이벤트)이지만 노드의 컨텍스트에서는 비동기 서버 작업(예: File I/O 접근, Network I/O)을 말한다.
이러한 차이로 인해 Chrome(크롬)과 노드는 동일한 V8 엔진을 사용하지만 다른 이벤트 루프 구현체를 가지고 있다.
이벤트 루프는 프로그래밍 패턴이라서 V8에서는 Javascript 런타임과 함께 작동하도록 외부 이벤트 루프 구현체을 가져와서 쓸 수 있게 했다.
크롬브라우저는 libevent를 이벤트 루프 구현체로 사용하며 노드는 libuv를 사용한다. 그러므로 크롬, 노드의 이벤트 루프는 다른 라이브러리 라서 차이점도 있지만 이벤트 루프라는 프로그래밍 패턴의 유사점도 공유한다.
브라우저,노드 이벤트 루프의 차이
브라우저와 노드의 차이점중 하나는 Micro-tasks(마이크로 태스크)와 Macro-tasks(매크로 태스크)중 어떻게 우선 순위를 정하냐의 차이이다.
마이크로 태스크와 매크로 태스크의 차이?
마이크로 테스크와 매크로 태스크는 비동기 작업의 2가지 유형을말한다.
그러나 마이크로 태스크가 매크로 태스크보다 우선 순위가 더 높다.
마이크로 태스크의 예는 Promise이며 매크로 테스크는 setTimeout 이다.
Node 버전 v11이상에서는 브라우저와 동작이 일치하지만 그 미만 버전에서는 차이가 발생한다.
HTML5 스펙에 따르면 이벤트 루프는 하나의 매크로 태스크를 처리한 후에 모든 마이크로 태스트 큐를 처리해야한다.
setTimeout1 콜백이 실행될 때 promise 콜백이 스케쥴링된다. 타이머 콜백 큐안에 있는 다른 타이머 콜백으로 이동하기 전에 이벤트 루프는 마이크로 태스크 큐가 비어있다는게 확인해야합니다. 따라서 추가된 promise 콜백을 실행합니다. 그리고 나서 마이크로 태스크 큐가 비어지면 타이머 콜백 큐에 있는 setTimeout2 콜백을 처리합니다.
하지만 노드 v11 미만에서는 마이크로 태스크 큐는 이벤트 루프의 phase 사이에서만 끌어올수 있다. 그러므로 setTimeout 안에 있는 promise 콜백은 모든 타이머 콜백이 실행이 되기전까지는 기회를 얻지 못한다.
중첩된 타이머 동작
노드에서는 setTimeout 0으로 해도 최소 1ms 후에 실행된다.
크롬에서는 중첩된 4번째 타이머까지는 최소 1ms를 가지지만 그 이후로는 최소 4ms후에 실행된다.
HTML 스펙에 따르면 중첩된 타이머가 5개이상이면 최소 4ms 간격으로 실행된다.
이 규칙에 따라 브라우저는 5번쨰 중첩된 타이머부터 적용된다.
process.nextTick 및 setImmediate
브라우저에는 nextTick, setImmediate가 존재하지 않는다.
nextTick 콜백은 노드의 libuv 이벤트 루프의 일부가 아니다. 이벤트 루프의 각 단계로 이동하기 전에 nextTick 큐가 실행된다.