【Node.js 入門 #1】 Node.js とは? JavaScript をサーバーサイドで実行しよう!
新年あけましておめでとうございます🎍
仙台オフィスの上松です。今年もよろしくお願いします!
昨年のBubble入門シリーズはいかがでしたか?
皆様がローコードに興味を持つきっかけとなっていたら嬉しく思います。
さて、今年は打って変わってゴリゴリにプログラミングの記事を書いていこうと思います。
題材は Node.js です。
JavaScript に詳しい方なら「あぁ、アレね!」と思われる方も多いかもしれません。
一方で、Node.js という名前は聞いたことがあるけれど、実際にはよくわからない…という方も少なくないと思います。
本記事では、Node.js とは何かについて、関連でよく出てくる JavaScript や、その JavaScript と名前がよく似ている Java との違いを交えながらご紹介します。
さらに Node.js の内部の仕組みや実際の用途についても解説していきます。
本記事を読めば、Node.js ? めっちゃいいよね!となっていただけるはず…!!
それでは、Let's node!!
目次
- Node.js とは何か
- JavaScript のサーバーサイド実行環境
- JavaScript との違い
- Java との違い
- Node.js の仕組み
- シングルスレッドでの JavaScript 実行
- イベントループとノンブロッキングI/O
- スレッドプール
- Node.js の用途
- Node.js が採用される理由
- Node.js が適している分野
- Node.js が適していない分野
- Biz Freak における使用例
- まとめ
Node.js とは何か
JavaScript のサーバーサイド実行環境
Node.js は、JavaScript の実行環境です。
2009年に Ryan Dahl (ライアン・ダール)氏によって開発されました。
通常、JavaScript は Web ブラウザ上で動作するプログラミング言語として知られています。
Web ページの構造を操作する DOM 操作や、ボタンクリックなどのイベントを処理するイベントハンドリングを使って、ページの見た目や動きを動的に変えるために使われてきました。
しかし Node.js の登場により、JavaScript はサーバーサイドでも実行できるようになりました。
平たく言えば、Web ブラウザ外のコンピュータ上で JavaScript が使えるようになった、ということです!
Web ブラウザ上の JavaScript では、セキュリティやユーザーのプライバシー保護のために以下のような処理が制限されています。
- ローカルファイルの読み書き
- データベースの操作
- HTTPサーバーの構築
- そのほか Web ブラウザ外のコンピュータ上のリソースへのアクセス
しかしながら、Web ブラウザ外の JavaScript を実行環境を提供する Node.js が登場したおかげで、本来ならば他のプログラミング言語(Python や Java)にその役割を譲らなければならなかった上記のようなコンピュータ上の処理を JavaScript だけで書けるようになったのです。
JavaScript との違い
Node.js と JavaScript の違いを理解することは重要です。
以下の観点から比較してみましょう。
プログラミング言語としての位置づけ
- JavaScript: プログラミング言語そのもの
- Node.js: JavaScript を実行するための環境(プログラミング言語ではない)
動作環境
- JavaScript: Web ブラウザ上、または Node.js 上で実行
- Node.js: コンピュータ上で直接実行(サーバーやローカルマシン)
Java との違い
本記事をお読みの方は Java を触ったことのある方が何名かいらっしゃるのではないでしょうか?
仙台オフィスのある東北地方では、プログラミング言語といえば 産業構造的に Java が支配的です。
筆者は過去に JavaScript を「Java」もしくは単に「スクリプト」と呼ぶ方々に出会ったことがあります。
前者は新人研修で Java を習い始めたばかりの未経験の方で、後者は Web 開発に疎いご年配の SE でした。
残念ながらどちらの呼び方も他のエンジニアからは誤りと受け取られてしまいます。
Node.js とは切っても切り離せない JavaScript 。
そんな JavaScript と非常に紛らわしい Java との違いをここではっきりさせておくべきでしょう。
余談: なぜ名前が紛らわしいか?
第一次ブラウザ戦争(1990年代)、それは Netscape Communications 社のブラウザ『NetScape Navigator』と Microsoft 社の ブラウザ『Internet Explorer』が覇権争いをしていた時代でした。
争いの中で NetScape 社は JavaScript を発明しましたが、当初は LiveScript という名前でした。その頃は Sun Microsystems 社の新興プログラミング言語 Java の人気が凄まじく、さらに Netscape Communications 社は Sun Microsystems 社と業務提携を結んでいたこともあってか、Java 人気にあやかろうとして LiveScript を JavaScript と改名してしまいます。
... 全く別の言語であるにもかかわらず。
それだけ『Netscape Navigator』はライバルの『Internet Explorer』を打倒したかったのでしょうか。
プログラミング言語としての関係
- JavaScript: Java とは全くの別物(名前が似ているだけ)
- Java: JavaScript とは全くの別物(名前が似ているだけ)
プログラミングパラダイム(作法)
- JavaScript: 手続き型、オブジェクト指向、関数型と柔軟
- Java: 厳格なオブジェクト指向
型システム
- JavaScript: 動的型付け(実行時に型チェック)※ TypeScript は静的型付け
- Java: 静的型付け(コンパイル時に型チェック)
主な用途
- JavaScript/Node.js: Web 開発全般(フロントエンド、バックエンド)
- Java: 大規模業務システム、Android アプリ開発など
採用する企業の傾向
- JavaScript/Node.js: 主に新興のIT企業(Web 系、SaaS 系、スタートアップ界隈)
- Java: 主に伝統的なIT企業(SIer/SES界隈)
Node.js の仕組み
Node.js がどのようにプログラムを実行するのか学びましょう。
シングルスレッドでの JavaScript 実行
まず Node.js は JavaScript を 「シングルスレッド」で実行します。
これは「1本の処理の道」しか持っていないということです。
例えば、レストランのキッチンを想像してください。
シングルスレッドは「シェフが1人しかいないキッチン」のようなものです。
一度に1つの料理しか作れません。
// 重い計算処理の例
function heavyCalculation() {
let result = 0;
for(let i = 0; i < 1000000000; i++) {
result += Math.random();
}
return result;
}
このような重い計算を実行すると、その間は他の処理ができなくなってしまいます。
シェフが1人なので、ある料理に集中している間は他の注文を捌けないのと同じですね。
イベントループとノンブロッキング I/O
でも、実際のレストランでは1人のシェフでも複数の料理を同時に進められますよね。
オーブンで焼いている間に、新しいオーダーを受け付けたり、次の料理の下準備をしたりする、など。
Node.js も同じような工夫をしています。
それが「イベントループ」と「ノンブロッキング I/O」です。
まずは I/O(Input/Output)について説明しましょう。
I/O とは「データの入出力」のことです。
例えば…
- ファイルの読み書き
- ネットワーク通信
- データベースへのアクセス
など、プログラムの外とデータをやり取りする処理のことを指します。
これらの処理は時間がかかります。
ハードディスクからデータを読み込んだり、インターネットを通じてデータを送受信したり...。
私たちにとってはほんの一瞬ですが、コンピュータの世界では「とても長い待ち時間」なのです。
では、Node.js はこの「待ち時間」をどう扱うのでしょうか? レストランの例で考えてみましょう。
シェフ(Node.js のメインスレッド)は、以下のように効率的に調理を進めます。
// 調理の流れ
const kitchen = require('kitchen');
// ステーキを調理する場合
kitchen.cookSteak('beef', (err, steak) => {
if (err) {
console.error('調理失敗:', err);
return;
}
console.log('ステーキの完成:', steak);
});
console.log('ステーキを焼いている間に他の作業を始めます');
イベントループとは:
- シェフ(Node.js)が常に「次は何をやるべきか」をチェックし続ける仕組み
- 「オーブンのタイマーが鳴った」「新しい注文が来た」といった出来事(イベント)を見逃さない
- これらのイベントに対して、適切なタイミングで対応できる
ノンブロッキング I/Oとは:
- 「待ち時間のある作業」を「邪魔にならない方法」で処理する仕組み
- 例:ステーキをオーブンで焼いている間(I/O処理)、シェフは別の作業ができる
- もし「ブロッキング」だと:シェフがオーブンの前で待ち続けなければならない
- 「ノンブロッキング」なら:タイマーをセットして別の作業ができる
このように、待ち時間が発生する処理(I/O 処理)は「裏方の設備に任せる」ことで、メインの処理を止めることなく効率よく実行できるのです。
スレッドプール
先ほどの例で、シェフはオーブンやレンジを使って効率的に調理を進められると説明しました。
でも、実際のレストランには他にも便利な設備がありますよね。
- 食器洗浄機
- 製氷機
- 食材の冷蔵庫
- 換気扇
これらの設備は「同時に」動いています。シェフが料理に集中している間も、食器は洗浄され、氷は作られ、食材は適温で保管され続けます。
Node.js の世界でも同じことが起きています。「スレッドプール」は、このような「裏方の設備」に相当します。
// 同時に複数の作業を行う例
const kitchen = require('kitchen');
// 食器洗浄を開始
kitchen.washDishes('dirty-plates', (err, cleanPlates) => {
console.log('食器洗浄完了');
});
// 氷の製造を開始
kitchen.makeIce(5, (err, ice) => {
console.log('氷の製造完了');
});
// 食材の温度チェックを開始
kitchen.checkFridgeTemp('vegetables', (err, temp) => {
console.log('野菜の保管温度:', temp);
});
console.log('シェフは調理に専念できます');
このように、Node.js のスレッドプールは
- 複数の I/O 作業を同時に処理できる「裏方の設備」
- シェフ(メインスレッド)の作業を邪魔しない
- 黙々と仕事をこなして、終わったら報告してくれる
という特徴を持っています。
このおかげで、1人のシェフでも効率的にレストランを切り盛りできます。
シェフは料理に集中し、裏方の設備たちが並行して様々な作業を進める...。
Node.js はこのような孤独なチームワークによって効率的な動作を実現しています。
余談: 「Node.js はシングルスレッドである」は本当?
個人的には間違ってはいないけれど誤解を招く表現かなと考えております。
JavaScript の実行がイベントループに従ってシングルスレッド上で動作している、というのがより正確な表現かと思います。
なぜなら Node.js にはスレッドプール(デフォルトで4つのスレッド)が別に内蔵してあるからです。
Node.js の用途
Node.js の仕組みが見えてきたところで、次はその用途を探ってみましょう。
Node.js が採用される理由
Node.js はモダンな IT 企業で採用される傾向があります。
Node.js は本来、JavaScript のサーバーサイド実行環境として誕生しました。
ノンブロッキング I/O の仕組みによりネットワーク通信を多用するシステムのバックエンド開発において大きな強みを発揮します。
参考: C10K問題
そもそも Node.js は「 C10K問題」を解決することが誕生の背景にあったと言われています。
C10K問題とは、Webサーバーにクライアント1万台くらいが同時接続してくると、Webサーバーのハードウェア的な性能とは無関係に、ソフトウェア的にコンピュータ内のリソースが枯渇して、Webサーバーの応答が遅くなってしまう問題です。
当時のWebサーバーの主流は、クライアントが接続されるたびに新規で丸々プロセスを生成するか、クライアントごとにスレッドを生成するのが普通でした。Node.js は全く逆のアプローチで、クライアント数がどれだけ増えようともシングルスレッドでのみ接続を受け付け、I/Oの処理はノンブロッキングな形で別のスレッドプールに委譲することによって、コンピュータ内のリソースを節約しつつ、コンテキストスイッチを抑制することに成功しました。
しかし最近では、それ以上に注目すべき特徴があります。
それは、技術トレンドが目まぐるしく変化するフロントエンド開発との一体性です。
Node.js は JavaScript の実行環境であると同時に、この変化の激しいフロントエンド開発の基盤となる環境でもあるのです。
フロントエンド開発との一体性
- フロントエンド開発で培った JavaScript の知識をバックエンドでもそのまま活用可能
- npm を通じてフロントエンド・バックエンド両方のパッケージを一元管理
- Webpack や Vite といったフロントエンド開発に必須のビルドツールは Node.js で利用可能
新技術・新トレンドの即時導入
- ECMAScript の新機能をブラウザの実装を待たずに利用可能
- 半年ごとのメジャーバージョンアップにより最新の JavaScript 機能を常に活用
- TypeScript など、フロントエンド開発の最新プラクティスをすぐに採用可能
このような特徴から、Node.js は小規模でスピード感のある開発現場との相性が良いと言えます。
特にスタートアップや新規事業では、少人数の体制でネットワーク通信を含むバックエンド機能を堅実に実装しながら、同時にフロントエンド開発の最新トレンドも素早く取り入れることも求められるため、Node.js がとても頼りになります。
一方で、継続的なアップデートが計画されておらず頻繁に改善をリリースする文化がない開発現場では Node.js の採用はやめておいたほうが得策でしょう。
Node.js 自体も、npm で提供されるパッケージも、メンテナンスを怠ると瞬く間に古びてしまうためです。
Node.js が適している分野
Node.js は、その特性から特に以下のような分野との相性が良いことが知られています。
Webアプリケーションのバックエンド
- リクエスト数の多い REST APIサーバー や GraphQL サーバー
- WebSocket を使用したリアルタイム通信サーバー
- マイクロサービスのゲートウェイやプロキシサーバー
これらは Node.js のノンブロッキング I/Oによる恩恵を最大限受けられる分野です。
ブロッキング な I/O が発生しないため、大量のネットワーク接続を効率的に処理できます。
マイクロサービスでは、前方に Node.js を置き多数の接続を受けつけて、重い計算処理は後方に控える他の言語に任せる構成が考えられます。
開発環境のツールチェーン
- TypeScript の開発環境
- React や Vue などモダンフロントエンドの開発環境
- Webpack や Vite などのモジュールバンドラーの実行
- ESLint や Prettier などのコード品質管理ツールの実行
近年では上記両方の特性を兼ね備えている Next.js というフルスタックフレームワークが大流行しています。
Node.js が適していない分野
先ほどのレストランの例えで考えてみましょう。
Node.js はシングルスレッドで JavaScript を実行、つまり「シェフが1人」のレストランのような仕組みで動いています。
このシェフは、オーブンやレンジなどの設備(I/O処理)をうまく使って、効率的に複数の料理を同時に進めることができます。
しかし、以下のような作業は苦手です。
料理人自身の手作業が多い料理
- 大量の野菜の微細な飾り切り
- 複雑な手作業が必要な和菓子作り
- 休むことなく包丁を振り続けるような作業
プログラミングの世界では、これらは以下のような処理に相当します。
CPU バウンドな処理
- 機械学習の推論処理(大量の数値計算)
- 画像・動画のエンコード(ピクセルごとの演算処理)
- 暗号化・復号処理(連続的な数学的計算)
このような「料理人自身の手作業」が多い処理では、1人しかいない料理人がその作業に専念している間、他の注文を全く捌けなくなってしまいます。
そのため、このような処理が多い場合は、
- Go(最初から複数のシェフが揃っているレストラン)
- Rust(担当範囲が明確な複数のシェフが協力しているレストラン)
と言った他のプログラミング言語(実行環境)を検討してもよいと思います。
技術選定は、そのレストランでどんな料理を主に提供するのか、どのくらいの客数を想定するのかによって変わってきます。
Node.js のレストランは、大量のオーダーを受け付けつつ、オーブンやレンジをフル活用するような料理(I/O処理)が得意と言えます。
Biz Freak における使用例
Biz Freak では例えば、ビルの状態を見える化および制御するシステムにおいて、ビル内にある多数の機器とリアルタイムに双方向通信する際に大活躍しています。
このようなネットワーク I/O が激しい環境で Node.js は真価を発揮します。
なぜならば、Node.js のイベントループとノンブロッキング I/O の仕組みにより、大量の同時接続を効率的に処理できるからです。
- メインスレッドでイベントループを回し、I/O 処理はスレッドプールに委譲する設計であることにより、I/O 待ちによるブロッキング(無駄な待ち時間)を避けられる
- コールバックや Promise といったノンブロッキングな非同期処理のパターンを活用することで、複数の接続を同時に管理しながらもメモリ消費を抑えることができる
net
やsocket.io
といった通信用のライブラリが充実しており、多数の機器との双方向通信を簡単に実装可能
1000台の機器からセンサーデータを毎秒受信しながら、それぞれの機器に制御コマンドを送信するような処理も、Node.js なら比較的少ないコードと少ないコンピュータリソースで実装可能です。
まとめ
本記事では Node.js の基本概念から仕組み、実際の用途まで幅広く解説しました。
JavaScript をサーバーサイドで実行できる Node.js は、現代の Web 開発において避けては通れないと言っていいほどの中核的な技術の1つとなっています。
Node.js での開発に興味をお持ちの方は、是非とも Biz Freak へ!
特に仙台オフィスのある東北地方の方は、そろそろ React とか Vue で齧ったことのある Node.js を本格的に触ってみたくありませんか?
プログラミング言語は Java や PHP だけじゃないですよ!
Biz Freak では Node.js に限らずローコードや生成AIなど幅広く技術に触れることができます。
👉 https://bizfreak.co.jp/recruit
次回は Node.js のインストールをして Hello World をかましつつ、変数宣言のコツをご紹介します。
実際のコードを書きながら、Node.js を一歩ずつ学んでいきましょう!
したらばまた!ノシ