https://nodejs.org/ko/learn/asynchronous-work/event-loop-timers-and-nexttick
Node.js가 시작되면 이벤트 루프를 초기화하고 제공된 입력 스크립트를 처리하거나 비동기 API 호출, 일정 타이머 또는 호출을 수행한 다음 이벤트 루프 처리를 시작합니다.
이벤트 루프의 연산 순서를 간략하게 나타낸 것입니다.
┌───────────────────────────┐
┌─>│ timers │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
│ │ pending callbacks │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
│ │ idle, prepare │
│ └─────────────┬─────────────┘ ┌───────────────┐
│ ┌─────────────┴─────────────┐ │ incoming: │
│ │ poll │<─────┤ connections, │
│ └─────────────┬─────────────┘ │ data, etc. │
│ ┌─────────────┴─────────────┐ └───────────────┘
│ │ check │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
└──┤ close callbacks │
└───────────────────────────┘
각 단계에는 실행할 콜백의 FIFO 큐가 있습니다. 각 단계는 고유한 방식으로 특별하지만 일반적으로 이벤트 루프가 주어진 단계에 진입하면 해당 단계에 특정한 모든 작업을 수행한 다음 큐가 소진되거나 최대 콜백 수가 실행될 때까지 해당 단계의 큐에서 콜백을 실행합니다. 큐가 소진되거나 콜백 제한에 도달하면 이벤트 루프가 다음 단계로 이동합니다.
이러한 작업 중 하나라도 더 많은 작업을 예약할 수 있고 폴 단계에서 처리되는 새 이벤트가 커널에 의해 큐에 추가되므로 폴링 이벤트가 처리되는 동안 폴링 이벤트가 큐에 추가될 수 있습니다. 결과적으로 장기 실행 콜백은 폴 단계가 타이머 임계값보다 훨씬 더 오래 실행될 수 있도록 허용할 수 있습니다.
1. 큐에 작업이 있을때의 동작
아래의 동작이 차례대로 실행됩니다.
- timers: setTimeout( ), setInterval( ) 에 의해 스케줄된 callback들이 수행된다. (설정된 임계값까지 poll의 시기를 제어)
- pending callbacks: 다음 loop로 미뤄진 I/O 콜백이 수행된다.
- idle, prepare: 내부적으로 사용. (사용자 정의 작업과는 관련이 없음 / 시스템이 사용)
- poll: 새로운 I/O 이벤트를 가져와서 I/O와 관련된 callback을 수행한다. (사용자가 정의 부분 실행)
- check: setImmediate( ) 에 의해 스케줄된 callback들이 수행된다. (setImmediate는 setTimeout보다 항상 우선적으로 실행)
- close callbacks: socket.on('close', ...) 와 같이 close와 관련된 callback이 수행된다.
참고로 Microtask Queue을 통해서 테스크가 관림되며 Promises나 process.nextTick은 우선순위가 높다.
setTimeout(() => console.log('Timeout'), 0);
setImmediate(() => console.log('Immediate'));
Promise.resolve().then(() => console.log('Promise'));
process.nextTick(() => console.log('NextTick'));
# 출력
NextTick
Promise
Immediate
Timeout
2. 큐가 비어 있을 때의 동작
큐가 비어 있는 상태에서 이벤트 루프는 Poll Phase에서 멈추며, 다음 동작상태가 됩니다.
(1) I/O 이벤트 대기
- Poll 단계는 새로운 I/O 이벤트가 도착하기를 기다리는 단계입니다.
- 이 단계에서는 OS 수준에서 지원하는 비동기 I/O 대기 메커니즘(예: epoll(Linux), kqueue(macOS), IOCP(Windows))을 활용합니다.
- 새로운 I/O 이벤트가 발생하면, 해당 콜백이 큐에 추가됩니다.
(2) Idle 상태로 전환
- 만약 실행할 작업이 없고 새로운 I/O 이벤트도 발생하지 않는 경우, 이벤트 루프는 CPU를 절약하기 위해 대기 상태로 전환합니다.
- 대기 상태에서는 OS 수준에서 효율적으로 리소스를 사용하며, 불필요한 반복 작업을 피합니다.
(3) 프로세스 종료 조건
- 이벤트 루프는 아래 조건에서만 종료됩니다
- 모든 타이머가 종료됨.
- 모든 I/O 작업이 완료됨.
- 작업 대기 큐가 비어 있고, 실행할 콜백도 없음.
- 종료 예약된 작업(process.exit)이 호출됨.
3. 만일 하나의 콜백이 너무 많은 작업을 한다면?
이벤트 루프 특성한 실행되는 콜백은 중간에 멈출수가 없다. (위의 poll 단계에서 계속 실행중이게 된다. )
이러면 모든 작업이 멈추게 되므로 (싱글스레드이기 떄문에) 다음과 같이 쪼개서 작업해야 한다.
- 작업을 비동기적으로 나누기 (aync/await)
- Worker Threads 활용
'Node.js > 1. node.js 란?' 카테고리의 다른 글
1-4. 콜백 지옥 (0) | 2025.01.06 |
---|---|
1-3 node.js의 단점! (0) | 2025.01.06 |
1-2 node.js의 특징. event-driven, non-blocking I/O , 단일 스레드 (0) | 2025.01.06 |
1-1 node.js 는 무엇일까요? (1) | 2014.02.13 |