본문 바로가기
js/작동방식

node 비동기 작업의 실행원리 (process.nextTick)

by 냉면돈가스 2024. 12. 5.

node는 기본적으로 단일 스레드로 작동된다.

그러므로 setTimeout과 같은 비동기 호출이 들어왔을때 지정된 시간이 지난다면

메인 스레드의 실행큐에 전달돼 현재작업 이후에 실행된다.

setTimeout(() => {
  console.log(2);
}, 1000);

while (true) console.log(1);

 

위와 같은 코드는,

node 메인 스레드의 비동기작업을 담당하는 queue에 담겨 대기하다가 1초뒤에 실행 queue로 옮겨지겠지만,

이미 실행 queue는 독점하고있는 "console.log(1)" 라는 실행자원이 있기때문에 우리가 2라는 숫자를 볼 일은 없을것임

즉 setTimeout을 쓴다고 바로 실행되지않고 실행요청을 하는것이라고 이해하는게 좋을듯

 

아래 소스코드를 실행하면 어떻게될까?

setTimeout(() => {
  console.log(2222222222222222222222222222222222222222);
}, 1);

let running = true;

setTimeout(() => {
  running = false; // 3초 후에 루프 종료
}, 3000);

while (running) console.log(1);

 

running이란 변수를 false로 바꿔서 while문을 종료 후, 

"222222222222222222222222222" 를 출력해볼 심산이였겠지만

애초에 while이 쉬지않고 메인스레드의 실행 queue를 잡아먹고있는 이상

"running = false"가 실행될 일은 없다.

(더 자세히 알려면 아래로)


node의 동기작업과 비동기작업이 요청되었을때의 동작순서

(검증안된 내용입니다)

 

case 동기작업

동기작업은 즉시 콜스택에 담겨 순차적으로 실행

 

case 비동기 작업

비동기작업은 태스크 큐에 추가되어 이벤트 루프에 의해 콜스택으로 옮겨진 후에 완료됨

다만 바로 태스크 큐에 추가되는것이 아님

저마다의 비동기 작업을 수행한 후에 태스크 큐에 추가되는 것임

 

여기서 비동기작업이 setTimeout이라 하면, 대기시간이 있을것임

이 대기시간을 기다린 후에 이벤트 루프에 의해 콜스택으로 옮겨져야하는데,

대기시간이 다 되었는지 확인하는 역할은 이벤트 루프가 아니며

node.js 내부 라이브러리인 libuv가 스레드 풀이나 OS의 커널 스레드에서 수행되도록 전달한다.

(background 라고도 하는 듯)
OS의 커널 스레드의 타이머 기능을 이용하는 등 해서 비동기 작업을 수행한다.

 

background에서 비동기 작업을 완료 후,

콜백함수를 태스크 큐에 추가한 후에

이벤트 루프는 콜스택이 비었을때 태스크 큐에 있는 콜백함수를 콜스택으로 옮겨준다.

 

요약

1. 동기작업이 들어오면 콜스택에 담긴 후, 순차적으로 실행

2. 비동기 작업이 들어오면 libuv라는 내부 라이브러리에 의해 비동기 작업을 수행하는 "스레드 풀 or OS의 커널 스레드" 에 전달

3. 일명 background에서 비동기 작업 완료시 콜백함수를 전달받아 task queue에 담음

4. 이벤트루프는 task queue와 콜스택을 계속 검사하며, 콜스택이 비어있을시 task queue의 콜백함수를 콜스택으로 옮겨준다


바로 위의 문단을 읽은 후, 첫번째 문단을 다시 보자.

setTimeout(() => {
  console.log(2);
}, 1000);

while (true) console.log(1);

 

setTimeout은 스레드 풀이나 커널 스레드로 옮겨저 시간을 기다리는 비동기 작업을 수행하고있을것이다.

이는 콜스택이 비어있음을 뜻하며

"console.log(1);" 문장이 다음 콜스택을 차지한다..

setTimeout은 비동기 작업을 수행 후 task queue에 옮겨졌지만 while문에 의해 콜스택이 빠방한 상태.. 심지어 계속 채워진다.

그로인해 이벤트루프는 task queue에 콜백함수가 있는걸 확인했지만

콜스택이 비어있지 않기 때문에 setTimeout의 콜백함수를 콜스택으로 옮기지 못한다.

그래서 "2" 출력은 무한 대기 상태가 된다.


이벤트 루프의 페이즈

 

이벤트 루프의 페이즈 등 상세 단계를 파악하고

setTimeout과 process.nextTick의 실행요청시 어떻게 이벤트 루프가 동작하는지를 확인한다.

(포스팅 추가 예정)

 

 

 

 

'js > 작동방식' 카테고리의 다른 글

js 일급객체(함수)  (0) 2023.02.15
js 실행컨텍스트  (0) 2022.12.28
js node, npm, cli  (0) 2022.01.15
js hoisting  (0) 2022.01.14

댓글