node.js runtime

minseok·2023년 8월 29일
0
post-thumbnail

https://dev.to/lydiahallie/javascript-visualized-event-loop-3dif
https://github.com/nodejs/help/issues

1장

Node.js란?

크롬 V8 엔진으로 빌드된 자바스크립트 런타임
Node.js는 이벤트 기반, 논블로킹 I/O 모델을 사용해 가볍고 효율적
Node.js의 패키지 생태계인 npm은 세계에서 가장 큰 오픈 소스 라이브러리 생태계이다.

브라우저에 탑재된 V8 engine을 브라우저 밖으로 들고나왔다.
(여러 브라우저에서 사용되는 js engine중 우수함)




노드의 내부구조

single thread기반이며 node.js에 포함된 libuv는 thread pool을 사용한다.

Node.js 구성
1. Node.js Core Library
2. Node.js Bindings
3. v8, 
4. libuv

https://nodejs.org/ko/docs/guides
Node.js core concepts 섹션을 보면 도움이 된다.




libuv

  1. 노드의 특성인 이벤트 기반, 논블로킹 I/O 모델을 구현
  2. Network, I/O 비동기 요청은 OS에게 요청하고 OS에 요청할 수 없는 비동기 요청은 libuv가 담당한다.
  3. Window - IOCP ( core수 만큼 thread를 생성 ), Linux - AIO

libuv Docs
https://docs.libuv.org/en/latest/design.html




Event Loop

Single Thread이며 순서가 존재하는 큐를 순회하면서 비동기 요청을 처리한다.
비동기 작업을 실행 코드에서 발견할 때 Event Loop도 같이 초기화한다.
(js file에 동기 방식코드만 존재한다면 Event Loop가 동작하지 않음)

Event Loop는 모든 동기 코드가 종료된 이후에 동작한다.

이벤트 루프 : 이벤트 발생 시 호출할 콜백 함수들을 관리, 호출된 콜백 함수의 순서를 결정
태스크 큐 : 이벤트 발생 후 호출되어야 할 태스크가 존재


위의 이미지처럼 계속 Loop하며 작업을 처리한다.
[ Timers ] -> [ Pending callbacks ] -> [ Idle, Prepare ] -> [ Poll ] -> [ Check ] -> [ Callbacks ]

Timer Phase
setTimeout(), setInterval()로 스케줄링한 콜백을 호출,
최소 힙 자료구조로 관리, 당연하게도 루트 노드 하나만 확인하고 준비가 안되었다면 다음 phase로 넘어간다.

'3초가 지나면 호출한다'는 진짜 3초가 지나고 호출하는게 아니라
'최소 3초는 보장한다'라는 의미이다.

Pending Callbacks
이전 이벤트 루프 반복에서 수행되지 못한 I/O Callback, 시스템 실행 한도 제한에 도달할 때 까지 큐에 쌓인 모든 작업들이 처리,
이벤트 루프는 해당 큐의 모든 콜백을 수행한다.

Idle, PrePare Phase
Node.js의 내부적인 관리를 위한 페이즈, 코드에 직접적인 영향을 미치지 않음

Poll Phase
I/O Event를 다루는 Phase
(SetTimeout, SetImmediate, Close Callback을 제외한 모든 콜백이 실행)

  • 데이터베이스에서 쿼리를 보낸 후 결과가 왔을 때 호출되는 콜백
  • HTTP 요청을 보낸 후 응답이 왔을 때 호출되는 콜백
  • 파일을 비동기로 다 읽고 호출되는 콜백

특징

  • I/O Event는 Timer와 달리 큐에 담긴 순서대로 호출될 수 없음
  • 단순한 콜백 큐 사용 X
  • I/O 요청을 위해 사용되는 Socket File에 대한 정보를 가지고 있다.
  • OS가 준비가 되었다고 알리면 해당 Socket과 연관된 Callback을 호출한다.
  • 시스템 실행 한도 제한에 도달할 때 까지 큐에 쌓인 모든 작업들이 처리

Poll Queue에 당장 처리할 수 없는 상태가 된다면 Check Queue, Pending Queue, Close Queue를 확인해 처리해야 할 작업이 있다면 다음 Phase로 넘어간다.
특별히 할 작업이 없다면 특정 로직에 의해 산출된 시간만큼 대기한다.

Check Phase
setImmediate()만을 위한 Phase

process.nextTick - 같은 Phase에서 즉시 호출
setImmeiate - 다음 Tick에서 호출

Close Callback Phase
socket.on('close', () => {})과 같은 close나 destory이벤트 타입의 콜백을 처리,
해당 단계를 마치고 다음 루프에서 처리해야하는 작업을 확인 후 작업이 없다면 루프를 종료






nextTickQueue, microTaskQueue

libuv 외부의 큐, eventLoop phase와 상관없이 동작
nextTickQueue는 "processTickQueue"를 관리
microTaskQueue는 "resolve된 promise의 callback"을 관리

2개의 큐는 이벤트 루프와 관계없이 현재 실행 작업이 끝나면 바로 실행된다.
(여기서 실행 작업은 Phase가 아니라 실제 코드 실행 단위이며 아마.. 단위로 추측)

우선순위
nextTick > microTick

profile
즐겁게 개발하기

0개의 댓글