본문 바로가기

JavaScript/Node

Node.js 알아보기

안녕하세요 :)

 

JavaScript는 웹의 언어입니다. 익히 JavaScript는 브라우저 위에서 작동하는 클라이언트 언어라고 알려져 있죠. 혹시 이런 JavaScript가 브라우저에서만 작동한다고 알고 계셨나요? 예전에는 그랬을지 몰라도 현재는 Node.js라는 환경이 있기 때문에 전혀 그렇지 않습니다!

Node.js의 등장으로 JavaScript는 브라우저를 넘어 서버로, 그리고 훨씬 더 넓은 영역으로 확장되었습니다. 이제는 하나의 언어로 프론트엔드와 백엔드를 모두 개발할 수 있는 시대가 열린 것이죠.

 

출처: https://thevolteragroup.com/nodejs/

그렇다면 Node.js란 무엇이며, 어떻게 동작하는지 알아보는 시간을 가져보도록 하겠습니다.

 

Node.sj 란 무엇인가

Node.js는 JavaScript를 브라우저 없이 실행시킬 수 있는 런타임 환경입니다.

 

출처: https://dev.to/rahmanmajeed/javascript-the-runtime-environment-35a2

런타임 환경이 무엇일까요?

런타임 환경이란, 프로그램이 실행되기 위해 필요한 소프트웨어와 도구를 제공하는 환경입니다. Node.js의 런타임 환경은 JavaScript 코드 실행을 위해 V8 엔진과 파일 시스템, 네트워크와 같은 서버 기능을 제공합니다. 즉, 브라우저 없이도 JavaScript를 실행하고 서버 역할까지 할 수 있게 만드는 환경이라는 것이죠.

 

이런 Node.js 덕분에 JavaScript는 서버와 같은 백엔드 영역에서도 사용될 수 있게 되었습니다. Node.js는 Google의 V8 엔진 위에 구축되어 JavaScript를 빠르게 실행하고, 비동기 처리와 이벤트 기반 모델을 활용해 고성능 서버 개발에 적합한 환경을 제공하고 있습니다.

 

이렇게 좋은 Node.js는 어떻게 탄생하게 되었을까요?

 

Node.js의 탄생 배경을 알아보자

JavaScript는 원래 브라우저에서 DOM 조작과 사용자 인터페이스를 다루기 위해 설계된 언어였습니다. 하지만 브라우저 밖에서는 사용할 수 없다는 치명적인 한계를 가지고 있었죠.

 

https://en.wikipedia.org/wiki/Ryan_Dahl

이때, Ryan Dahl이라는 사람이 JavaScript의 비동기 처리 모델과 V8 엔진의 성능을 눈여겨 보고 있었습니다. 서버와 애플리케이션 로직을 JavaScript 하나로 통합할 방법을 고민하였고, 결국 Node.js를 탄생시켰습니다. 처음엔 리눅스와 macOS만 지원되었으나 2011년 7월 이후에는 Windows 버전도 발표되어, 현재는 폭넓게 사용되고 있습니다. 

 

탄생 배경도 간단히 알아보았으니, 어떻게 동작하는지 살펴볼까요?

 

Node.js의 동작 원리

 

Node.js는 싱글 스레드 기반의 Event Loop와 비동기 I/O 구조를 통해 효율적으로 동작합니다. 조금 더 자세히 볼까요?

출처: https://www.freecodecamp.org/news/what-exactly-is-node-js-ae36e97449f5/

 

1. 코드 실행

  • Node.js는 JS 코드를 실행합니다.
  • JS 코드를 실행하는 과정에서 동기적(Synchronous)코드는 바로 실행되고, 비동기적(Asynchronous) 작업은 백그라운드로 전달됩니다.

2. 비동기 작업 처리

  • Node.js는 비동기 작업(ex. 파일 읽기, 네트워크 및 데이터 요청 등)을 처리하기 위해 libuv라는 라이브러리를 사용합니다.
  • 이는 비동기 작업 처리를 위한 스레드 풀(Thread Pool)을 활용합니다.
const fs = require('fs');

fs.readFile('file.txt', 'utf8', (err, data) => {
    if (err) throw err;
    console.log(data);
});

console.log('파일 읽는 중 ~ ');
  • 코드의 실행 흐름을 보면,
    1. fs.readFile()은 비동기 작업이므로 libuv의 스레드 풀에 전달됩니다.
    2. console.log()는 동기 작업이기 때문에 먼저 실행되게 되며,
    3. 파일 읽기가 완료되면, 그 결과를 담은 콜백이 이벤트 큐로 이동합니다.

3. 백그라운드 스레드(Background Thread)

출처: https://en.wikipedia.org/wiki/Thread_pool

  • Node.js는 기본적으로 싱글 스레드로 동작하지만, libuv는 내부적으로 스레드 풀을 사용하여 I/O 작업(파일 읽기, 네트워크 및 데이터 요청 등)을 병렬 처리합니다.

4. 콜백 처리

  • 비동기 작업이 완료되면, 해당 작업의 콜백 함수가 이벤트 큐로 이동하게 됩니다.
  • 이벤트 큐는 작업이 완료된 비동기 작업을 담아두는 공간이죠.

5. 이벤트 루프(Event Loop)

  • Node.js의 이벤트 루프는 메인 스레드에서 동작하며 아래 작업을 반복하게 되는데,
    • Call Stack가 비어 있는지 확인
    • 이벤트 큐에서 대기 중인 작업인 콜백 함수들을 가져와 실행
    • 실행이 완료되면 다시 대기
  • 이벤트 루프의 동작을 예로 들어보자면,
    • 동기 작업이 콜 스택에서 실행
    • 비동기 작업이 libuv로 전달
    • 작업이 완료되면 이벤트 큐로 콜백 전달
    • 콜 스택이 비면 이벤트 큐에서 작업 실행

 

Node.js의 동작 흐름은 크게 이렇게 볼 수 있지만, 여기서 백그라운드 스레드 풀이 조금 햇갈릴 수 있으니 추가 설명을 붙여보겠습니다.

 

백그라운드 스레드 풀 (Background Thread Pool)

Node.js는 싱글 스레드 기반이지만, 비동기 작업을 처리하기 위해 내부적으로 libuv라는 라이브러리를 활용합니다. libuv는 스레드 풀(Thread pool)을 사용하는데, 이 스레드 풀이 JavaScript 코드 실행 외의 작업을 백그라운드에서 병렬로 처리합니다.

 

출처: https://www.scaler.com/topics/nodejs/thread-pool-and-os-operations/

 

백그라운드 스레드 풀의 역할을 살펴볼까요?

  1. I/O 작업 처리
    • 파일 읽기/쓰기, 데이터베이스 요청, 네트워크 요청 등
    • 시간이 오래 걸리는 작업을 메인 스레드 대신 백그라운드 스레드가 처리
  2. CPU 집약적 작업 처리
    • 암호화, 데이터 압축, 이미지 처리 등 CPU를 많이 사용하는 작업 처리

 

이러한 역할을 가진 스레드 풀은 이렇게 동작합니다.!

  1. 비동기 작업 요청
    • JS에서 비동기 작업을 호출하면, 이를 libuv가 처리하게 됩니다.
  2. 작업 위임
    • libuv는 작업을 스레드 풀로 전달하여 병렬로 실행하는데요.
    • 기본적으로 4개의 스레드가 사용되며, 필요에 따라 늘릴 수 있습니다.
    • UV_THREADPOOL_SIZE 라는 환경 변수를 설정하면 됩니다.
  3. 작업 완
    • 작업이 완료되면, 결과를 Event Queue로 보냅니다.
  4. 콜백 실행
    • 이제 이벤트 루프가 큐에 쌓인 콜백을 콜 스택으로 올려서 실행시키겠죠?

 

예시 코드를 보며 조금 더 살펴볼까요?

const crypto = require('crypto');

console.log('암호화  시작')

crypto.pdkdf2('password', 'salt', 100000, 64, 'sha512', () => {
    console.log('암호화 완료')
});

console.log('다른 작업 수행 중')
  • 실행 흐름을 보면,
    • crypto.pbkdf2는 비동기 작업으로 스레드 풀에 전달됩니다.
    • console.log()는 동기 작업이기 때문에 먼저 실행이 됩니다.
    • 암호화 작업이 완료되면, 콜백 함수가 이벤트 큐에 추가되고,
    • 이벤트 루프가 큐에서 콜백을 가져와 '암호화 완료'를 출력하게 됩니다.
  • 출력된 결과를 보면,

이런 순서로 결과가 출력됩니다.

 

이러한 백그라운드 스레드 풀 구조가 서버 개발에 적합한 구조를 제공하며, 비동기 병렬 처리를 효율적으로 하도록 도와주게 됩니다.

 

브라우저와 Node.js의 차이

원래 JavaScript는 브라우저 위에서만 동작하는 언어였습니다. 주로 클라이언트 사이드에서 DOM 조작과 사용자 인터페이스 관리를 위해 설계되었죠. 하지만 Node.js의 등장으로 더 이상 브라우저 환경에만 묶이지 않는 그런 뭐든지 가능한 언어가 되었습니다.

 

브라우저 환경의 대체제인 Node.js는 기존 브라우저와 어떤 차이가 있을까요?

특징 브라우저 Node.js
실행 환경 브라우저 위에서 실행됨 서버나 로컬 환경에서 실행됨(Node.js 설치는 필수)
역할 클라이언트 사이드 - DOM 조작, UI 업데이트, 사용자 이벤트 처리 서버 사이드 - 파일 시스템 접근, 데이터베이스 연결, 네트워크 처리, 데이터 요청 등
내장 API DOM, CSSOM, Fetch API, WebSocket 등  File System, HTTP, Stream, Buffer, Child Processess 등
비동기 처리 방식 Web API를 통한 비동기 처리 (ex. setTimeout, fetch 등) libuv를 통한 비동기 처리 (스레드 풀 및 이벤트 루프 활용)
의존성 브라우저의 엔진 및 API 사용 Node.js의 V8 엔진과 Node.js에서 제공하는 모듈 사용
모듈 시스템 ES Modules CommonJS 모듈 시스템 (require)과 ES Modules 모두 지원
사용 예시 웹 페이지에서 버튼 클릭 이벤트 처리, 화면에 데이터 렌더링 웹 서버 생성, 데이터베이스 쿼리 실행, 파일 시스템 조작

 

표로 대략적인 차이를 확인할 수 있으셨나요?

 

브라우저와 Node.js의 주요 구성 요소가 어떻게 되는지 조금 더 알아보겠습니다.

출처: https://www.geeksforgeeks.org/nodejs-vs-browser/

  1. 브라우저의 구성 요소
    • JavaScript 엔진
      • V8, SpiderMonkey 등 브라우저에서 JS를 실행하는 엔진
    • WebAPI
      • DOM, Fetch API, WebSocket 등 브라우저가 제공하는 기능
    • 렌더링 엔진
      • HTML, CSS를 해석하고 UI를 렌더링
    • Sandbox 환경
      • 브라우저는 보안상 로컬 파일 시스템이나 서버 자원에 직접 접근할 수 없음
  2. Node.js의 구성 요소
    • V8 엔진
      • Google의 JS 엔진, 브라우저 없이도 JS를 실행 가능하게 함
    • libuv
      • 비동기 I/O 처리를 위한 라이브러리.
      • 이벤트 루프와 스레드 풀을 제공
    • Node.js 내장 모듈
      • fs, http, os와 같은 모듈로 네이티브 자원에 접근 가능
    • npm
      • node package manager로 다양한 라이브러리와 툴 제공

 

브라우저와 Node.js의 비동기 처리 차이도 더 봐볼까요?

 

1. 브라우저 비동기 처리

  • WebAPI가 처리
  • JS 엔진은 비동기 작업을 WebAPI로 전달하고, WebAPI가 작업을 완료한 후 입네트 큐에 콜백 추가
setTimeout(() => console.log('Timeout'), 1000);
fetch('https://api.example.com/data'), then(response => console.log(response));

 

2. Node.js 비동기 처리

  • libuv가 비동기 처리의 핵심 역할을 담당
  • 비동기 작업이 libuv의 스레드 풀에서 처리된 후, 작업 완료 시 이벤트 큐로 콜백이 전달됨.
const fs = require('fs');

fs.readFile('file.txt', 'utf8', (err, data) => {
    if (err) throw err;
        console.log(data);
});

 

 

 

Node.js 한눈에 보기

지금까지 알아본 Node.js를 한눈에 표로 정리해보았습니다.

특징 설명
런타임 환경 JavaScript를 브라우저 없이 실행할 수 있게 하는 런타임 환경
비동기 처리 이벤트 루프와 libuv를 활용한 비동기 처리로 높은 동시성 제공
모듈화 및 확장성 npm을 통한 다양한 모듈과 라이브러리 활용
사용 사례 실시간 채팅, 데이터 스트리밍 등 다양한 분야
생태계 npm을 통한 방대한 라이브러리 생태계 지원

 

끝내는 말

오늘은 Node.js에 대해 알아보았습니다. Node.js는 JavaScript의 영역을 브라우저를 넘어 서버와 IoT, 실시간 애플리케이션 등으로 확장시킨 혁신적인 기술인데요. Node.js를 통해 개발자들은 하나의 언어로 클라이언트와 서버를 모두 다룰 수 있는 통합된 개발 환경을 체험할 수 있게 되었습니다.

 

쓰다보니까 내용이 너무 길어졌네용..ㅎ.ㅎ 

 

읽어주셔서 감사합니다 :)