Node.js 작동원리에 대한 개괄을 위에서 표현해두었다.
개발자가 작성한 소스코드에 의해 Application이 생성된다.
여기서 중요한 것은 Application 내부에 함수들을 순서대로 실행시키는 call stack
의 존재이다.
call stack
에 함수들이 차례대로 구동되다가 setTimeout()과 같은 함수가 발동될 때, 비동기로 실행된다.
setTimeout()과 같은 Timer함수, file, Network 같은 I/O 작업들 모두 Node.js에서 제공하는 API에 의해 실행된다.
Node.js는 이러한 API를 실행시켜놓고 제어권을 넘기지 않은 채로 call stack
의 다음 함수를 실행시킨다. (Non-Blocking I/O)
libuv는 node.js에서 비동기를 가능케 하며 Non-blocking I/O를 실행시킨다. node.js api에서는 multi Threading 방식으로 함수들을 실행시키고 작업이 완료되면 callback 함수를 libuv 내부의 Task Queue
로 던진다.
Node.js 작동의 핵심이라고 볼 수 있다.
Event loop에서 Call Stack
을 계속 확인하고 있다가 Call Stack
이 텅 비게 될 때, Task Queue
내부의 callback 함수를 하나씩 Call Stack으로 넘겨 실행시키게 된다.
이런 식으로 하다보니 Node.js API를 통해 발동되는 작업들은 바로바로 실행된다.
그래서 I/O 작업에는 효율적이라고 볼 수 있다.
하지만 결국 함수 실행은 Call Stack에서 하나씩 실행되기 때문에 TaskQueue에서 CallStack으로 전달되는 callback함수가 시간이 오래 걸리는 작업이라면 어플리케이션 전체가 느려진다. 따라서 경량의 I/O작업하는 어플리케이션이라면 Node.js가 적당하다고 볼 수 있다.
하지만 이마저도 Node.js 12버전부터 Worker Thread
의 등장으로 무거운 작업들을 커버할 수 있다고 한다. 이에 대해서는 다음에 알아보도록 하자.