Node.js는 Chrome의 V8 JavaScript 엔진 에 구축 된 JavaScript 런타임
비동기 이벤트 기반 JavaScript 런타임 인 Node.js는 확장 가능한 네트워크 애플리케이션을 빌드하도록 설계됨.
Event loop
- JavaScript가 싱글 스레드라는 사실에도 불구하고, 가능할때마다 작업을 시스템 커널로 offload하여 non-blocking IO 작업을 수행할 수 있도록 함
- 대부분의 최신 커널은 다중 스레드이므로 백그라운드에서 실행되는 여러 작업을 처리 가능
- 이러한 작업 중 하나가 완료되면, 커널은 Node.js에 적절한 콜백을 poll queue에 추가하여 실행되도록 함
- Node.js가 시작되면, 이벤트 루프를 초기화하고 제공된 input script를 처리하여 async API 호출, 스케쥴 타이머, process.nextTick() 호출을 수행할 수 있음
- 그런 다음에 이벤트 루프 처리를 시작
- 각 단계에는 실행할 callback의 FIFO 대기열이 존재
- 일반적으로 이벤트 루프가 주어진 단계에 진입하면 해당 단계에 특정한 작업을 수행한 다음 대기열이 소진되거나 최대 콜백 수에 도달할 때까지 해당 단계의 대기열에서 콜백을 실행함
- 대기열이 소진되었거나, 콜백 limit에 도달하면, 이벤트 루프가 다음 단계로 이동하는 방식
- 폴링 이벤트가 처리되는 동안 폴 이벤트가 큐에 추가될 수 있음
각 단계 설명
timers
- setTimeout() 및 setInterval()에 의해 예약된 콜백을 실행
- 주어진 콜백이 실행될 수 있는 임계값을 지정
- timer callback은 지정된 시간(임계값)이 지나면 스케쥴링할 수 있을 때 최대한 빨리 실행 (하지만 운영 체제 스케쥴이나 다른 콜백 실행으로 인해 지연될 수 있음)
- 기술적으로는 poll 단계는 timers가 실행되는 시기를 제어
pending callbacks
- 다음 loop 반복으로 지연된 I/O 콜백을 실행
- TCP 오류와 같은 시스템 동작에 대한 콜백을 실행
ex) TCP 소켓이 연결을 시도할 때 'ECONNREFUSED'를 수신하면, 일부 *nix 시스템은 오류보고를 기다림. 그럼 pending callback에서 실행될 수 있도록 queue에 추가됨
idle, prepare
(내부적으로 사용)
poll
- 새로운 I/O 이벤트를 검색
- I/O 관련된 콜백(ex. close callback의 예외, timer에 의한 스케쥴, setImmediate())을 실행
- 노드는 적절한 경우 여기에서 차단됨
주요 기능
1. I/O를 block과 polling 해야하는 기간을 계산
2. poll queue의 event 처리
이벤트 루프가 poll 단계에 들어가고, 예약된 타이머가 없으면 다음 2가지 중 1개가 발생됨
- poll queue가 비어있지 않은 경우 : 이벤트 루프는 큐가 소진되거나 system-dependent 하드 한계에 도달할 때까지 동기식으로 실행하는 콜백 큐를 반복
- poll queue가 비어있는 경우
-- script가 setImmediate()에 의해 스케쥴된 경우 : 이벤트 루프는 풀 단계를 종료하고, 예약된 스크립트를 실행하기 위해 check단계를 계속 수행
-- script가 setImmediate()에 의해 예약되지 않은 경우 : 이벤트 루프는 콜백이 대기열에 추가될 때까지 기다린 다음 죽시 실행
- poll queue가 지면 이벤트 루프는 시간 임계값에 도달한 타이머를 확인
- 하나 이상의 타이머가 준비된 경우, 이벤트 루프틑 timers 단계로 다시 래핑되어 해당 타이머의 콜백을 실행
check
- setImmediate() 콜백이 여기서 호출
- 이 단계에서 poll 단계가 완료된 후 즉시 콜백을 실행 가능
- poll 단계가 유휴 상태가 되고, 스크립트가 setImmediate()로 대기열에 추가된 경우, 이벤트 루프는 대기하지 않고 check 단계를 계속할 수 있음
- setImmediate()는 실제로 이벤트 루프의 별도 단계에서 실행되는 특수 타이머
- poll 단계가 완료된 후 실행할 콜백을 예약하는 libuv API를 사용
- 일반적으로 이벤트 루프는 들어오는 connection, request 등을 기다리는 poll 단계에 도달
- 그러나 callback이 setImmediate()로 예약되고, poll 단계가 유휴 상태가 되면 poll 이벤트를 기다리지 않고 종료되며, check 단계를 계속 수행
close callbacks
- 일부 close callback (ex. socket.on('close')...)
- 소켓이나 handler가 갑자기 닫히면, 이 단계에서 'close' 이벤트가 발생함 ex) socket.destroy()
- 그렇지 않으면 process.nextTick()를 통해 방출됨
이벤트 루프가 실행될 때마다, Node.js는 비동기 I/O나 timer가 대기중인지 확인하고 없는 경우 완전히 종료
setImmediate() vs setTimeout()
- 두 함수는 비슷하지만 호출 시기에 따라 다른 방식으로 작동
- 타이머가 실행되는 순서는 호출되는 내용에 따라 다르고, 두 함수 모두 기본 모듈 내에서 호출되는 경우 타이밍은 프로세스의 성능에 의해 결정됨
setImmediate()
- poll 단계가 완료되면 script를 실행하도록 설계됨
setTimeout()
- ms 단위의 최소 임계값이 경과한 후에 script가 실행되도록 예약
setTimeout() 보다 setImmediate()를 사용하는 가장 큰 이유는 I/O 주기 내에 스케쥴링된 경우 setImmediate()가 항상 타이머 수에 관계없이 먼저 실행됨
process.nextTick()
- 비동기 API 중 하나
- nextTickQueue는 이벤트 루프의 현재 작업 중인 단계에 관계없이 현재 작업이 완료된 후에 처리
※ 작업 : c/c++ 처리기에서 전환하고 실행해야하는 JavaScript를 처리하는 것
- 각 단계에서 process.nextTick()을 호출할 때 마다, process.nextTick()에 전달된 모든 콜백은 이벤트 루프가 계속되기 전에 해결됨
-- 이벤트 루프가 poll 단계에 도달하는 것을 방지하는 재귀적 process.nextTick() 호출을 만들어 I/O를 "starve"시킬 수 있기 때문에
RangeError: Maximum call stack size exceeded from v8
process.nextTick() vs setImmediate()
- process.nextTick()은 같은 단계에서 즉시 실행됨
- setImmediate()는 이벤트 루프의 다음 반복 또는 'tick'에서 발생
- 즉_ process.nextTick()은 setImmediate() 보다 즉시 실행됨
- 개발자들은 모든 경우에 setImmediate()를 사용하는 것을 권고
process.nextTick()은 언제 써?
- 사용자가 오류를 처리하고, 불필요한 리소스를 정리하거나, 이벤트 루프가 계속되기 전에 request를 다시 시도해야하는 경우
- call stack이 풀린 후 이벤트 루프가 계속되기 전에 콜백이 실행되도록 허용해야 하는 경우
출처
https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/
'Programming > JavaScript & TypeScript' 카테고리의 다른 글
Strict mode(엄격 모드), use strict 란? (0) | 2020.09.29 |
---|---|
JavaScript의 Decorator (0) | 2020.09.28 |
npm install 시 npm ERR! code EINTEGRITY 에러 해결 방법 (0) | 2020.09.22 |
[Angular5] translate 현재 사용중인 언어 가져오기 (0) | 2020.09.22 |
호이스팅 (Hoisting) (0) | 2020.09.15 |