Node.js: Node.js 入門
アリスはバックエンド開発者です。彼女が勤める会社では、2週間以内にモバイルアプリ用のREST APIバックエンドを構築する必要がありました。チームはJavaScriptしか知らないフロントエンド開発者だけで構成されており、新しい言語を学ぶ時間を割こうとする者は誰もいませんでした。プロジェクトマネージャーはPython開発者を採用することも検討しましたが、どうしても時間が足りませんでした。チームが不安を感じ始めていたちょうどその時、アリスはNode.js——サーバー上でJavaScriptを実行するランタイム——を発見しました。フロントエンド開発者は、すでに慣れ親しんだ構文を使ってバックエンドAPIを記述することができ、プロジェクトは2週間後に無事に公開されました。この経験を通じて、アリスはNode.jsが単なるツールではなく、フロントエンドとバックエンドをつなぐ架け橋であることに気づいたのです。
学習内容:
- Node.js の定義と主な目的
- V8エンジンとNode.jsの基盤となるアーキテクチャ
- イベント駆動型およびノンブロッキングI/Oの仕組み
- Node.js とブラウザ用 JavaScript の主な違い
- Node.js のバージョン管理方針と代表的なユースケース
1. Node.js とは?
(1) 定義
Node.js は、Chrome の V8 エンジンを基盤とする JavaScript 実行環境です。これにより、ブラウザに依存することなく、サーバー上で直接 JavaScript を実行することが可能になります。Node.js は新しい言語でもフレームワークでもなく、JavaScript 用のサーバーサイド実行プラットフォームです。
(2) その起源の背景
2009年、ライアン・ダールはV8エンジンを基盤としてNode.jsを開発しました。彼の当初の目標は、サーバー側のI/O操作によって引き起こされるブロッキングの問題を解決することでした。従来のWebサーバーでは、ファイルの読み取りやネットワークリクエストなどのI/O操作を処理する際にスレッドがブロックされてしまいますが、Node.jsはイベント駆動型のアプローチを採用しており、単一のスレッドで多数の同時接続を効率的に処理することが可能です。
▶ サンプル:初めての Node.js スクリプト
ファイル hello.js を作成:
console.log('Hello, Node.js!');
console.log('Node.js version:', process.version);
console.log('Platform:', process.platform);
ターミナルで次のコマンドを実行してください:
node hello.js
期待される出力:
Hello, Node.js!
Node.js version: v20.11.0
Platform: win32
2. V8エンジンとNode.jsのアーキテクチャ
(1) V8エンジンの役割
V8は、Googleが開発したJavaScriptエンジンであり、JavaScriptコードをマシンコードにコンパイルして実行します。Node.jsにはV8エンジンが組み込まれているため、これほど高いパフォーマンスを発揮するのです。V8のジャストインタイム(JIT)コンパイル技術により、JavaScriptはネイティブコードに近い速度で実行されます。
(2) Node.js のアーキテクチャ層
Node.jsのアーキテクチャは、下から順に4つの層に分かれています:
| レベル | 構成 | 機能 |
|---|---|---|
| JavaScript コード層 | ユーザーが作成した .js ファイル | ビジネスロジック |
| Node.js API レイヤー | fs、http、path などのモジュール | サーバーサイドの機能を提供 |
| Node.js バインディング層 | C++ ブリッジコード | JavaScript と基盤となる C ライブラリの連携 |
| 低レベルライブラリ | V8、libuv、OpenSSL など | エンジンとシステムコール |
(3) libuvの重要な役割
libuv は Node.js の非同期 I/O ライブラリであり、イベントループ、スレッドプール、および非同期 I/O 向けのクロスプラットフォームな抽象化機能を提供します。これにより、Node.js はファイル I/O、ネットワーク操作、タイマーなどの非同期操作を、さまざまなオペレーティングシステム間で一貫した方法で処理できるようになります。
▶ サンプル:Node.js の依存関係情報の確認
console.log('V8 version:', process.versions.v8);
console.log('libuv version:', process.versions.libuv);
console.log('OpenSSL version:', process.versions.openssl);
console.log('Node.js version:', process.version);
出力:
V8 version: 11.3.244.8
libuv version: 1.46.0
OpenSSL version: 3.0.12
Node.js version: v20.11.0
▶ サンプル:(4) アーキテクチャ図
graph TB
A["JavaScript Code<br/>(User-written .js Documents)"] --> B["Node.js API<br/>(fs / http / path / ...)"]
B --> C["Node.js Bindings<br/>(C++ Bridge Layer)"]
C --> D1["V8 Engine<br/>(JavaScript Compile and Run)"]
C --> D2["libuv<br/>(Event Loop + Asynchronous I/O)"]
C --> D3["Other C Libs<br/>(OpenSSL / zlib / c-ares)"]
D2 --> E["Operating System<br/>(Documents / Internet / Process)"]
3. イベント駆動型およびノンブロッキングI/O
(1) イベント駆動型モデル
Node.js はイベント駆動型アーキテクチャを採用しています。つまり、プログラムは能動的にポーリングを行うのではなく、イベントコールバックを登録することで、さまざまな操作に応答します。I/O 操作が完了すると、イベントループは対応するコールバックをキューに入れ、実行を待ちます。
(2) ノンブロッキングI/Oの意味
従来のサーバーでは、ファイルの読み込み中は、ファイルが完全に読み込まれるまで現在のスレッドをブロックします。一方、Node.js では、I/O リクエストを開始した後、直ちに処理を返し、その後のコードの実行を継続し、I/O 操作が完了したらコールバックを介して結果を処理します。このアプローチにより、単一のスレッドで数百もの同時リクエストを同時に処理することが可能になります。
(3) イベントループの概要
イベントループは Node.js のコアとなるスケジューリング機構であり、以下のフェーズをループして実行されます:
- 時間:setTimeout / setInterval のコールバックを実行する
- 保留中のコールバック:システム操作を実行するコールバック
- アイドル、準備:内部用
- poll:新しいI/Oイベントを取得し、I/Oコールバックを実行します
- 確認:setImmediateのコールバックを実行する
- close コールバック:close イベントのコールバックを実行する
▶ サンプル:ブロッキングとノンブロッキングのファイル読み取り
ブロッキングモード(推奨されません):
const fs = require('fs');
const data = fs.readFileSync('/etc/hosts', 'utf8');
console.log('File read (blocking):', data.length, 'bytes');
console.log('This line runs after file is read');
ノンブロッキングモード(推奨):
const fs = require('fs');
fs.readFile('/etc/hosts', 'utf8', (err, data) => {
if (err) throw err;
console.log('File read (non-blocking):', data.length, 'bytes');
});
console.log('This line runs immediately');
出力(ノンブロッキングモード):
This line runs immediately
File read (non-blocking): 250 bytes
なお、ノンブロッキングモードでは、最初に「This line runs immediately」と出力されます。これは、readFileが後続のコードをブロックしなかったことを示しています。
4. Node.js 対 ブラウザ用 JavaScript
(1) 主な相違点
Node.js とブラウザ上の JavaScript は、同じ言語仕様(ECMAScript)を使用していますが、その実行環境や利用可能な API はまったく異なります。
| 比較基準 | Node.js | ブラウザのJavaScript |
|---|---|---|
| 実行環境 | サーバー | ブラウザ |
| モジュールシステム | CommonJS / ESM | ESM |
| グローバルオブジェクト | グローバル / プロセス | ウィンドウ / ドキュメント |
| ファイルシステム | fs モジュールによる直接アクセス | 直接アクセス不可 |
| ネットワーク I/O | HTTP / ネットワークモジュール | fetch / XMLHttpRequest |
| DOMの操作 | DOMなし | DOM API |
| パッケージマネージャー | npm | なし(またはCDN経由) |
| 主な用途 | サーバーアプリケーション、CLIツール | Webとのやり取り、UIのレンダリング |
(2) 類似点
- すべてECMAScript規格に準拠しています
- どちらもV8エンジンを使用している(ChromeとNode.js)
- どちらも Promise / async-await をサポートしています
- これらすべてにイベントループの仕組みが備わっている
▶ サンプル:同じ構文、異なるAPI
ブラウザのコード:
document.getElementById('output').textContent = 'Hello from browser';
Node.js のコード:
const fs = require('fs');
fs.writeFileSync('output.txt', 'Hello from Node.js');
JavaScriptの構文は同じですが、操作対象となるオブジェクトはまったく異なります。ブラウザはDOMを操作するのに対し、Node.jsはファイルシステムを操作します。
5. Node.jsの代表的な活用例
(1) REST API サービス
Node.js は RESTful API の構築に最適です。そのノンブロッキング I/O モデルにより、多数の同時リクエストを効率的に処理でき、また JSON は JavaScript のネイティブなデータ形式であるため、シリアライゼーションのオーバーヘッドが排除されます。
(2) CLIツール
Webpack、Babel、ESLint、npm はすべて、Node.js を使用して構築された CLI ツールです。Node.js は、ファイルシステム、子プロセス、およびコマンドライン引数を扱うための豊富な API セットを提供しています。
(3) リアルタイムアプリケーション
チャットシステム、オンラインコラボレーション、リアルタイム通知といったシナリオでは、永続的な双方向接続が必要です。Node.jsのWebSocketサポートとイベント駆動型アーキテクチャは、こうしたニーズに当然ながら非常に適しています。
(4) マイクロサービス
Node.js は起動が速く、メモリ使用量も少ないため、軽量なマイクロサービスに最適です。各マイクロサービスは個別にデプロイおよびスケーリングが可能です。
(5) ウェブクローリングとデータ収集
Cheerioなどのライブラリと組み合わせることで、Node.jsはWebデータを効率的にクロールおよび解析することができ、非同期I/Oにより並行リクエストの処理が極めて効率的になります。
▶ サンプル:ユースケースの比較
| シナリオ | メリット | 代表的なプロジェクト |
|---|---|---|
| REST API | ノンブロッキングI/O + ネイティブJSON | Express / Fastify / Koa |
| CLI ツール | ファイル操作 + サブプロセス | Webpack / Babel / ESLint |
| リアルタイムアプリケーション | WebSocket + イベント駆動型 | Socket.IO / ws |
| マイクロサービス | 軽量でセットアップが簡単 | NestJS / Seneca |
| ウェブスクレイピング | 非同期並行処理 + DOM 解析 | Puppeteer / Cheerio |
▶ サンプル:5行のコードでHTTPサーバーを作成する
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ message: 'Hello from Node.js API' }));
});
server.listen(3000, () => console.log('Server running on port 3000'));
node server.js
Server running on port 3000
JSONレスポンスを確認するには、http://localhost:3000 にアクセスしてください。
6. Node.js のバージョンに関する方針
(1) LTS と現行版
Node.js はデュアルトラック方式のリリース戦略を採用しています:
| 比較 | LTS(長期サポート) | 現行 |
|---|---|---|
| リリースサイクル | 2年に1回のメジャーリリース | 6ヶ月に1回のメジャーリリース |
| 保守期間 | 30ヶ月 | 約6ヶ月 |
| 安定性 | 高;バグ修正とセキュリティパッチのみが含まれる | 低;最新の機能が含まれる |
| ユースケース | 本番環境 | 新機能の試用・テスト |
| バージョン番号の付け方 | 偶数(18、20、22…) | 奇数(19、21、23…) |
(2) バージョンの選び方に関する推奨事項
- 制作プロジェクト:常にアクティブなLTSバージョンを使用してください
- 学習段階:最も充実したリソースとエコシステムを提供している「Active LTS」の利用をお勧めします。
- 実験的機能:現在のバージョンは使用可能ですが、本番環境での使用は推奨されません。
(3) バージョン管理ツール
Node.js のバージョンの管理や切り替えには、nvm(Node Version Manager)の使用をお勧めします。
▶ サンプル:nvm を使ったバージョンの管理
nvm install 20
nvm use 20
nvm ls
v18.17.0
-> v20.11.0
system
default -> 20 (-> v20.11.0)
▶ サンプル:Node.js の現在のバージョンと状態を確認する
node -v
node -e "console.log(process.release.lts ? 'LTS: ' + process.release.lts : 'Current (non-LTS)')"
v20.11.0
LTS: Iron
❓ よくある質問
package.json or node_modules directory, and includes built-in formatting and testing tools in its standard library. The Deno ecosystem is still growing, while the Node.js ecosystem is more mature.node -v を実行して、正常に動作するか確認してください。📖 まとめ
- Node.js は、V8 エンジンを基盤とするサーバーサイドの JavaScript ランタイムであり、新しい言語というわけではありません。
- このアーキテクチャは、JavaScriptコード → Node.js API → バインディング → 基盤となるライブラリ(V8 / libuv)の4つの層で構成されています。
- イベント駆動型かつノンブロッキングI/Oは、Node.jsの高並行性を実現する中核となる仕組みです
- Node.js はブラウザの JavaScript と同じ構文を使用していますが、その API や実行環境はまったく異なります。
- 代表的な利用例:REST API、CLIツール、リアルタイムアプリケーション、マイクロサービス、ウェブクローラー
- 本番環境では必ずLTSバージョンを使用し、nvmを使って複数のバージョンを管理してください。
📝 練習問題
- Node.js(LTS版を推奨)をインストールし、
node -vを実行してインストールが正常に完了したことを確認した後、バージョン番号とLTS版であるかどうかをメモしておいてください。 hello.jsという名前のファイルを作成し、console.logを使って自分の名前と Node.js のバージョン番号を出力させ、それを実行してスクリーンショットを撮ってくださいprocessオブジェクトを使用して、Node.js のバージョン、OS のプラットフォーム、現在の作業ディレクトリ、および CPU アーキテクチャという情報を出力するスクリプトを作成してください。fs.readFileを使用して、テキストファイルをノンブロッキングモードで読み込み、その内容を出力し、コールバック関数の実行順序を確認する- 同じファイルを読み込む際に、コールバックの前後でそれぞれタイムスタンプを出力し、
fs.readFileSync(ブロッキング)とfs.readFile(ノンブロッキング)を比較して、両者の実行の違いを明らかにする。
7. 総合的な例:システム情報を読み取るスクリプト
以下のスクリプトは、Node.js の組み込みモジュールを使用してシステム情報を読み取り、出力するもので、サーバーサイドランタイムとしての Node.js の基本的な機能を示しています:
const os = require('os');
const fs = require('fs');
const path = require('path');
const sysInfo = {
nodeVersion: process.version,
platform: process.platform,
arch: process.arch,
hostname: os.hostname(),
totalMemoryMB: Math.round(os.totalmem() / 1024 / 1024),
freeMemoryMB: Math.round(os.freemem() / 1024 / 1024),
cpuCores: os.cpus().length,
cpuModel: os.cpus()[0].model,
uptimeHours: (os.uptime() / 3600).toFixed(2),
cwd: process.cwd(),
homedir: os.homedir()
};
const output = JSON.stringify(sysInfo, null, 2);
console.log(output);
const filePath = path.join(os.homedir(), 'nodejs-sysinfo.txt');
fs.writeFile(filePath, output, 'utf8', (err) => {
if (err) {
console.error('Write failed:', err.message);
return;
}
console.log('System info saved to:', filePath);
});
期待される出力:
{
"nodeVersion": "v20.11.0",
"platform": "win32",
"arch": "x64",
"hostname": "DESKTOP-ABC123",
"totalMemoryMB": 16384,
"freeMemoryMB": 8192,
"cpuCores": 8,
"cpuModel": "Intel(R) Core(TM) i7-12700K",
"uptimeHours": "48.32",
"cwd": "C:\\projects\\node-demo",
"homedir": "C:\\Users\\Alice"
}
System info saved to: C:\Users\Alice\nodejs-sysinfo.txt
このスクリプトは、Node.js の 3 つの主要な機能、すなわちオペレーティングシステム情報の取得 (os)、ファイルへの書き込み (fs)、およびパスの処理 (path) を実演しています。また、ファイルへの書き込みにはノンブロッキングI/Oが使用されています。fs.writeFileのコールバックはconsole.logの後に実行され、Node.jsのイベント駆動型の性質を示しています。