# Node.js là gì? Môi trường chạy JavaScript ngoài trình duyệt

> Node.js là runtime JavaScript dựa trên V8 engine và libuv, dùng kiến trúc event loop và I/O không chặn để xử lý hàng nghìn kết nối trên một luồng.

Nguồn: https://camnangai.com/ky-thuat/nodejs-la-gi  
Xuất bản: 2026-08-07

**Node.js** là một môi trường thực thi (runtime) [JavaScript](https://camnangai.com/ky-thuat/javascript-la-gi) mã nguồn
  mở, đa nền tảng, cho phép chạy JavaScript bên ngoài trình duyệt — cụ thể là phía máy chủ hoặc trực
  tiếp trên hệ điều hành.

Ryan Dahl giới thiệu Node.js lần đầu vào năm 2009 cho hệ điều hành Linux, và từ năm 2012 nó bắt đầu
được hỗ trợ chính thức trên Windows.

Sự xuất hiện của Node.js giúp bạn dùng một ngôn ngữ duy nhất cho cả
[frontend](https://camnangai.com/ky-thuat/lap-trinh-frontend-la-gi) và [backend](https://camnangai.com/ky-thuat/lap-trinh-backend-la-gi).
Việc này làm giảm đáng kể hiện tượng "context shift" (thay đổi ngữ cảnh) khi lập trình, và cho phép
bạn chia sẻ logic xác thực dữ liệu hay các kiểu dữ liệu [TypeScript](https://camnangai.com/ky-thuat/typescript-la-gi)
giữa hai phía.

Thay vì chỉ tương tác với giao diện người dùng qua các Web API, Node.js cung cấp cho JavaScript khả
năng làm việc với hệ thống tệp, mạng và các tiến trình hệ điều hành. Đây là nền tảng để xây
dựng các hệ thống backend chịu tải cao và các ứng dụng thời gian thực.

![Node.js đưa JavaScript ra khỏi trình duyệt để chạy trên máy chủ, hình ảnh chủ đề của bài viết](https://camnangai.com/articles/nodejs-la-gi/01-infographic-vn.webp)

## Node.js là gì?

**Node.js** không phải là một ngôn ngữ lập trình (ngôn ngữ thực thi vẫn là JavaScript), không phải
là một framework (như Express hay NestJS) và cũng không phải là một web server đơn thuần. Nó là một
runtime được xây dựng từ ba thành phần chính:

1.  **V8 JavaScript Engine:** Bộ máy do Google phát triển, không chỉ thông dịch mà còn sử dụng cơ chế
    JIT (Just-In-Time) compilation. V8 biên dịch trực tiếp JavaScript thành mã máy và tối ưu hóa các
    "hot code paths" (những đoạn mã chạy đi chạy lại nhiều lần) dựa trên runtime profiling, giúp mã
    thực thi với hiệu suất tiệm cận các ngôn ngữ biên dịch.
2.  **Thư viện libuv:** Một thư viện C chuyên trách quản lý Event loop và Thread pool. Quan trọng
    hơn, libuv cung cấp khả năng xử lý I/O bất đồng bộ ở cấp độ hệ điều hành (OS-level async I/O),
    cho phép Node.js xử lý hàng nghìn kết nối mà không bị treo luồng.
3.  **Hệ thống API:** Các module tích hợp sẵn để tương tác với File System, Networking và Child
    Processes.

![Ba thành phần tạo nên Node.js: V8 engine, thư viện libuv và bộ module hệ thống](https://camnangai.com/articles/nodejs-la-gi/02-vn.webp)

Node.js đóng gói JavaScript vào một môi trường có thể can thiệp sâu vào tài nguyên hệ thống, điều mà
trình duyệt bị hạn chế nghiêm ngặt vì lý do bảo mật. Đổi lại, bạn cũng mất luôn cái lưới an toàn mà
trình duyệt dựng sẵn cho mình.

## Node.js khác gì JavaScript chạy trong trình duyệt?

Dù cùng dùng chung cú pháp JavaScript, hệ sinh thái và API giữa hai môi trường này phân hóa rõ rệt.
Trong [trình duyệt](https://camnangai.com/ky-thuat/trinh-duyet-hoat-dong-nhu-the-nao), bạn làm việc với DOM, Window hoặc
Cookies để thao tác trên UI. **Node.js** lược bỏ hoàn toàn các API này vì chúng vô nghĩa trên server.
Thay vào đó, nó cung cấp các module như `fs` (truy cập tệp tin), `http` (giao thức mạng) hay
`streams` (xử lý dữ liệu lớn).

![So sánh hai môi trường: trình duyệt với DOM, Window, Cookies và Node.js với fs, http, streams cùng quyền truy cập hệ điều hành](https://camnangai.com/articles/nodejs-la-gi/03-vn.webp)

Bạn hoàn toàn kiểm soát được môi trường chạy Node.js. Trong khi lập trình viên frontend thường phải
dùng Babel để chuyển đổi mã về ES5 nhằm hỗ trợ các trình duyệt cũ, thì với Node.js, bạn chủ động chọn
phiên bản runtime trên server. Điều này cho phép sử dụng các tính năng mới nhất của ECMAScript mà
không cần thêm bước chuyển đổi phức tạp.

Về hệ thống module, Node.js hỗ trợ cả CommonJS (`require`) và ES Modules (`import`). `require` hoạt
động đồng bộ, còn `import` của ES Modules là bất đồng bộ, và đây là chi tiết mà tôi cho là dễ bị bỏ
qua nhất khi bạn thiết kế kiến trúc nạp module cho hệ thống.

## Event loop và I/O không chặn hoạt động ra sao?

**Node.js** sử dụng mô hình đơn luồng (single-threaded) nhưng vẫn đạt thông lượng (throughput) cao
nhờ cơ chế I/O không chặn (non-blocking I/O). Hãy hình dung qua phép ẩn dụ về "người bồi bàn": thay
vì đứng đợi tại một bàn cho đến khi bếp nấu xong món, người bồi bàn (luồng chính) lấy yêu cầu, gửi
vào bếp (libuv), rồi lập tức sang bàn khác phục vụ. Khi bếp làm xong, bồi bàn nhận được thông báo để
mang món ra cho khách.

![Vòng lặp sự kiện: luồng chính nhận yêu cầu, đẩy tác vụ nặng xuống thread pool của libuv rồi nhận kết quả qua callback](https://camnangai.com/articles/nodejs-la-gi/04-vn.webp)

Event loop thực chất hoạt động qua nhiều giai đoạn (phases) như: _timers_ (xử lý `setTimeout`),
_poll_ (nhận I/O mới) và _check_ (xử lý `setImmediate`). Ngoài ra, các microtasks (như Promises) sẽ
được giải quyết triệt để sau mỗi phase, trước khi vòng lặp chuyển sang phase tiếp theo.

Các tác vụ nặng như File I/O, Crypto hay Zlib sẽ được libuv đẩy xuống Thread pool (mặc định có 4
thread) để xử lý dưới nền, tránh làm nghẹt luồng chính. Một server HTTP tối giản trông như sau:

```javascript
const http = require("http");

const server = http.createServer((req, res) => {
  res.writeHead(200, { "Content-Type": "text/plain" });
  res.end("Hello World\n");
});

server.listen(8000, "127.0.0.1", () => {
  console.log("Server running at http://127.0.0.1:8000/");
});
```

Trong ví dụ này, hàm callback trong `createServer` chỉ được gọi khi có request tới, hoàn toàn không
chặn các hoạt động khác của hệ thống. Cả kiến trúc Node gói gọn trong chữ "chỉ" đó.

## npm và hệ sinh thái gói của Node.js

Trình quản lý gói npm đi kèm với **Node.js** hiện là kho lưu trữ phần mềm lớn nhất thế giới, với hơn
2,1 triệu gói tính đến năm 2024. Nó giúp tự động hóa toàn bộ chuỗi công cụ build và quản lý phụ
thuộc (dependency), nhờ đó các đội phát triển giảm được chi phí làm MVP và rút ngắn thời gian đưa
sản phẩm ra thị trường. Con số 2,1 triệu gói nghe thì oai, nhưng nó cũng có nghĩa là bạn đang đặt
niềm tin vào code của hàng nghìn người lạ.

Nhưng một hệ sinh thái lớn cũng đi kèm rủi ro về chuỗi cung ứng. Hãy chạy `npm audit` thường xuyên để
kiểm tra lỗ hổng bảo mật trong cây phụ thuộc. Với các dự án doanh nghiệp, kiểm soát gói bên thứ ba
bằng lockfile và quét lỗ hổng là quy trình bắt buộc để thu hẹp bề mặt tấn công của hệ thống.

## Khi nào nên dùng Node.js — và khi nào không?

Việc chọn **Node.js** cần dựa trên bản chất của tải công việc (workload):

- **Trường hợp nên dùng:** Các tác vụ hướng I/O (I/O-bound) là nơi Node.js thể hiện hiệu quả cao
  nhất. Ứng dụng chat, streaming, game online hoặc kiến trúc microservices cần xử lý hàng nghìn kết
  nối đồng thời với độ trễ thấp là kịch bản lý tưởng. Về hiệu suất, Node.js có thể đạt throughput
  khoảng 30.000 req/s trong điều kiện I/O-bound, vượt xa con số ~5.000 req/s của Python/Django.
- **Trường hợp KHÔNG nên dùng:** Các tác vụ tính toán nặng (CPU-bound) như xử lý video, mã hóa dữ
  liệu phức tạp hoặc AI/ML. Do tính chất đơn luồng, một vòng lặp tính toán nặng sẽ chiếm dụng call
  stack, làm "đứng" Event loop và chặn đứng mọi yêu cầu khác của người dùng.

![Hai loại tải: tác vụ hướng I/O mà Node.js xử lý rất tốt, và tác vụ nặng CPU làm nghẽn vòng lặp sự kiện](https://camnangai.com/articles/nodejs-la-gi/05-vn.webp)

Từ phiên bản v12, Node.js đã có Worker Threads để xử lý đa luồng cho các tác vụ CPU-bound, nhưng
giải pháp này buộc bạn phải cân nhắc chi phí truyền dữ liệu giữa các thread
(serialization/deserialization), và nó vẫn là miếng vá chứ không phải cách Node được thiết kế để
chạy.

## Nên bắt đầu với phiên bản nào?

Trong môi trường thực tế (production), bạn hãy luôn ưu tiên phiên bản
**LTS (Long Term Support — hỗ trợ dài hạn)**. Chu kỳ hỗ trợ của một phiên bản LTS kéo dài 30 tháng
(18 tháng Active và 12 tháng Maintenance), đủ để hệ thống của bạn nhận các bản vá bảo mật mà không bị
cuốn theo những thay đổi lớn về API.

Để quản lý nhiều dự án với các phiên bản **Node.js** khác nhau, công cụ chuẩn là NVM (Node Version
Manager), và nó giúp bạn chuyển đổi môi trường tức thì mà không gây xung đột hệ thống. Lệnh cài
phiên bản LTS mới nhất:

```bash
nvm install --lts
```

## Tài liệu tham khảo

- [About Node.js — Node.js](https://nodejs.org/en/about)
- [Overview of Blocking vs Non-Blocking — Node.js Learn](https://nodejs.org/learn/asynchronous-work/overview-of-blocking-vs-non-blocking)
- [Don't Block the Event Loop (or the Worker Pool) — Node.js Learn](https://nodejs.org/learn/asynchronous-work/dont-block-the-event-loop)
- [Differences between Node.js and the Browser — Node.js Learn](https://nodejs.org/learn/getting-started/differences-between-nodejs-and-the-browser)
- [Node.js Releases — Node.js](https://nodejs.org/en/about/previous-releases)
- [Express/Node introduction — MDN](https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/Introduction)
- [What Exactly is Node.js? Explained for Beginners — freeCodeCamp](https://www.freecodecamp.org/news/what-is-node-js/)
- [Node.js Backend Development: What It Is, How It Works, and How to Start — Netguru](https://www.netguru.com/blog/pros-cons-use-node.js-backend)
