원문 : https://amplication.com/blog/nodejs-asynchronous-flow-control-and-event-loop
Node.js의 강력한 비동기 이벤트 기반 아키텍처는 논블로킹 I/O 작업을 통해 확장성이 뛰어나고 효율적인 애플리케이션을 만들 수 있도록 서버 사이드 개발에 혁명을 일으켰습니다. 그러나 Node.js의 비동기 흐름 제어 및 이벤트 루프의 내부 동작을 파악하는 것은 초보자와 숙련된 개발자 모두에게 상당히 어려울 수 있습니다. 이 글에서는 이벤트 루프, 비동기 API, Node.js 콜스택과 같은 핵심 구성 요소를 포함해 Node.js의 비동기적 특성을 살펴보겠습니다.
비동기 흐름은 주요 프로그램 흐름이 차단되지 않도록 Node.js가 처리하고 실행하는 방식을 말합니다. 크롬의 V8 자바스크립트 엔진을 기반으로 구축된 서버 사이드 런타임 환경인 Node.js는 동시 작업을 효율적으로 관리하고 리소스 활용을 최적화합니다. 파일 I/O, 네트워크 요청, 데이터베이스 쿼리 등 다양한 작업을 별도의 백그라운드 스레드에 위임하여 메인 스레드가 다른 작업을 진행할 수 있도록 함으로써 이를 달성합니다. 백그라운드 작업이 완료되면 결과는 콜백, 프로미스 또는 async/await 메커니즘을 사용하여 메인 스레드로 반환됩니다. 이러한 접근 방식을 통해 Node.js는 응답성과 확장성을 유지할 수 있으므로 여러 동시 작업을 효과적으로 처리할 수 있는 논블로킹 고성능 애플리케이션을 구축하는 데 선호됩니다.
Node.js의 비동기 흐름의 중심에는 작업을 효율적으로 관리하고 실행하는 데 중요한 역할을 하는 구성 요소인 이벤트 루프가 있습니다. 이벤트 루프는 비동기 작업을 효율적으로 스케줄링하고 실행하는 역할을 담당합니다. 이벤트 루프는 태스크 큐를 지속적으로 모니터링하여 메인 스레드가 유휴 상태가 되면 보류 중인 작업을 실행하여 Node.js의 응답성을 더욱 향상시키고 동시 작업을 원활하게 처리할 수 있도록 합니다. 이제 Node.js 이벤트 루프의 세부 사항을 자세히 살펴보고 이 루프가 Node.js의 비동기 흐름을 어떻게 구동하는지 이해해 보겠습니다.
이벤트 루프는 비동기 작업을 효율적으로 관리할 수 있도록 해주는 Node.js의 핵심 요소입니다. 이벤트 루프는 이벤트 큐에서 보류 중인 이벤트를 지속적으로 모니터링하여 애플리케이션의 응답성을 유지합니다. Node.js의 이벤트 루프는 간단하면서도 매우 효과적인 메커니즘을 따릅니다.
Source: https://www.geeksforgeeks.org/node-js-event-loop/
위 그림은 Node.js 이벤트 루프의 예시를 보여줍니다. Node.js가 시작되면 이벤트 루프가 초기화되고 입력 스크립트가 처리됩니다. 이 입력 스크립트에는 비동기 API 호출과 타이머 스케줄링이 포함될 수 있습니다.
Node.js는 libuv
라는 전용 라이브러리 모듈을 사용하여 비동기 작업을 처리합니다. 이 모듈은 Node의 기본 로직과 함께 libuv
스레드 풀로 알려진 특수 스레드 풀을 관리합니다. libuv
스레드 풀은 기본적으로 4개의 스레드로 구성되며, 이 스레드들은 이벤트 루프에 너무 많은 리소스를 필요로 하는 작업을 오프로드하는 역할을 담당합니다. 이러한 작업에는 I/O 작업, 커넥션 열기 및 닫기, setTimeouts
처리 등이 포함됩니다.
libuv
스레드 풀이 작업을 완료하면 해당 콜백 함수가 호출됩니다. 이 콜백 함수는 잠재적인 오류를 처리하고 기타 필요한 작업을 수행합니다. 그 후 콜백 함수가 이벤트 큐에 추가됩니다. 콜스택이 비게 되면 이벤트 큐의 이벤트가 처리되어 콜백을 콜스택에 배치하여 실행할 수 있습니다.
Node.js 이벤트 루프는 여러 단계로 구성되며, 각 단계는 특정 작업을 전담합니다. 아래 다이어그램은 이벤트 루프의 여러 단계에 대한 간략한 개요를 보여줍니다.
Source: https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick
위의 다이어그램에서 볼 수 있듯이 Node.js 이벤트 루프에는 다양한 유형의 작업을 처리하기 위한 여러 단계가 있습니다.
setTimeout()
및 setInterval()
에 의해 예약된 콜백을 실행합니다. 이러한 콜백은 지정된 시간이 경과한 후 가능한 한 빨리 트리거됩니다. 그러나 운영 체제 스케줄링이나 다른 콜백의 실행과 같은 외부 요인으로 인해 실행이 지연될 수 있습니다.setImmediate()
스크립트가 예약을 확인하고, 예약이 있다면 확인 단계를 진행하거나 새 콜백이 큐에 추가될 때까지 기다렸다가 즉시 콜백을 실행합니다. 폴링 큐가 비게 되면 이벤트 루프는 타이머가 시간 임계값에 도달했는지 확인하고, 도달한 경우, 타이머 단계로 다시 이동하여 해당 콜백을 실행합니다.setImmediate()
콜백을 호출합니다. 코드가 실행되면 이벤트 루프는 결국 폴링 단계에 도달합니다. 그러나 setImmediate()
를 사용하여 콜백이 예약되어 있고 폴링 단계가 유휴 상태가 되면 이벤트 루프는 폴링 이벤트가 발생할 때까지 기다리지 않고 바로 확인 단계로 진행됩니다.close
이벤트가 발생합니다. 그러나 즉시 종료가 아닌 경우에는 process.nextTick()
을 사용하여 close
이벤트가 발생합니다.Node.js의 비동기 흐름 제어를 포괄적으로 이해하려면 Node.js 콜스택과 비동기 API와의 상호 작용을 이해하는 것이 필수적입니다.
콜스택은 프로그램 내에서 함수 호출을 추적하는 데이터 구조로 동작합니다. 함수가 호출되면 스택의 맨 위에 추가되고, 완료되면 제거되는, 후입선출(LIFO)의 순서를 따릅니다. 아래 다이어그램에서 볼 수 있듯이 Node.js는 처음에 스크립트에 대한 전역 실행 컨텍스트를 생성하여 스택의 맨 아래에 배치한 다음 호출되는 각 함수에 대한 함수 실행 컨텍스트를 생성하여 스택에 배치합니다. 이러한 실행 컨텍스트의 스택을 콜스택이라고 합니다.
Source: https://www.javatpoint.com/javascript-call-stack
또한 Node.js는 비동기적으로 동작하도록 설계되었기 때문에 비동기 작업의 결과를 관리하기 위해 콜백 또는 프로미스를 사용하는 많은 API를 제공합니다. 비동기 함수가 호출되면 Node.js 런타임 환경으로 오프로드되어 이벤트 루프가 다른 작업을 계속 처리할 수 있습니다. 비동기 작업이 완료되면 연결된 콜백이 콜백 큐에 배치되어 이벤트 루프의 실행을 기다립니다. 콜스택이 비어 있으면 이벤트 루프는 콜백 큐에서 첫 번째 콜백을 선택해 실행을 위해 콜스택으로 푸시합니다. 이 접근 방식은 비동기 작업이 메인 스레드를 차단하지 않도록 하여 애플리케이션의 응답성에 기여합니다.
Node.js의 비동기적 특성은 다음과 같이 개발자와 개발자가 구축하는 애플리케이션에 도움이 되는 몇 가지 주목할 만한 이점을 제공합니다.
비동기식 특성은 놀라운 이점을 제공하지만, 개발자가 염두에 두어야 할 몇 가지 과제를 야기하기도 합니다. 다음은 몇 가지 일반적인 함정과 이를 극복하기 위해 권장되는 전략입니다.
비동기 프로그래밍은 대규모 동시 작업을 효율적으로 처리하는 강력한 패러다임입니다. Node.js는 뛰어난 동시성과 확장성을 달성하기 위해 이 접근 방식에 크게 의존합니다. 이벤트 루프, 비동기 API, Node.js 콜스택을 중심으로 하는 비동기적 특성 덕분에 비동기 작업을 효율적으로 관리할 수 있어 응답성이 뛰어난 애플리케이션을 제공할 수 있습니다.
비동기 흐름의 이점을 수용함으로써 개발자는 이벤트에 실시간으로 반응하는 고성능의 확장 가능한 애플리케이션을 개발하여 사용자에게 원활하고 효율적인 경험을 제공할 수 있습니다. 하지만 이벤트 루프가 차단되거나 콜백 지옥에 빠지는 등의 잠재적인 함정을 염두에 두고 원활한 실행과 오류 처리를 보장하기 위해 모범 사례를 채택하는 것이 중요합니다. 전반적으로 Node.js의 비동기적 특성은 최신 반응형 서버 사이드 애플리케이션을 구축하기 위한 강력한 기반을 제공합니다.
This is really helpful information thanks that you shared with us. ADP Workforce Now
”콜백 큐가 비어 있으면 이벤트 루프는 콜백 큐에서 첫 번째 콜백을 선택해 실행을 위해 콜스택으로 푸시합니다“
콜백큐가 비어있다가 아니라 콜 스택이 비어있다로 되어야할거 같습니다!