JavaScriptは、世界で最も人気のあるプログラミング言語のひとつです。今日、何百万ものウェブサイトを動かしており、ウェブ用の機能を構築するために多くの開発者やデザイナーを魅了しています。JavaScriptはプログラミングの経験を問わず注目したい、簡単に習得できる最高のプログラミング言語のひとつです。

最初の20年間、JavaScriptは主にクライアントサイドスクリプティングに使われていました。JavaScriptは<script> タグの中でしか使えなかったため、開発者はフロントエンドとバックエンドのコンポーネントの間で複数の言語やフレームワークを使って作業しなければなりませんでした。その後に登場したNode.jsは、JavaScriptで書かれたプログラムを実行するのに必要なすべてを含むランタイム環境です。

Node.jsは、高速でスケーラブルなサーバーサイドおよびネットワーキングアプリケーションを構築するのに便利な、シングルスレッド、オープンソース、クロスプラットフォームのランタイム環境です。V8 JavaScriptランタイムエンジン上で動作し、イベントドリブン、ノンブロッキングI/Oアーキテクチャを使用しているため効率的であり、リアルタイムアプリケーションに適しています。

Node.jsの記述言語

Node.jsはC、C++、JavaScriptで書かれています。

ウィキペディアはNode.jsを「GoogleのV8 JavaScriptエンジン、libuvプラットフォーム抽象化レイヤー、コアライブラリのパッケージコンパイルであり、それ自体は主にJavaScriptで書かれている」と定義しています。

ランタイムは、JavaScript実行エンジンであるChrome V8を内部で使用し、C++で記述されています。これにより、Node.jsのレパートリーに、内部システム機能(ネットワークなど)へのアクセスなど、さらなるユースケースが加わっています。

Node.jsのアーキテクチャとその仕組み

Node.jsは、複数のクライアントを同時に処理する「シングルスレッドイベントループ」アーキテクチャを使用しています。これが他のランタイムとどのように異なるかを理解するには、Javaなどの言語でマルチスレッドの同時クライアントがどのように処理されるかを理解する必要があります。

マルチスレッドリクエストレスポンスモデルでは、複数のクライアントがリクエストを送信し、サーバーはレスポンスを送り返す前にそれぞれのリクエストを処理します。しかし、同時呼び出しの処理には複数のスレッドが使われます。スレッドはスレッドプールで定義され、リクエストが来るたびに個々のスレッドが割り当てられ処理されます。

Nodejs-Architecture
イベントループを使ったNode.jsのリクエスト処理方法

Node.jsの動作をステップ毎に見てみましょう。

  1. Node.jsは、リクエストに対応する限られたスレッドプールを保持する。
  2. リクエストが来るたびに、Node.jsがそれをキューに入れる。
  3. ここで、シングルスレッドの「イベントループ」(コアとなるコンポーネント)が効果を発揮。このイベントループが継続的にリクエストを受け入れる。
  4. リクエストが来ると、ループがキューからそれをピックアップし、入出力(I/O)のブロック操作を必要とするかどうかをチェック。そうでなければ、リクエストを処理してレスポンスを送る。
  5. リクエストにブロック操作が必要な場合、イベントループは内部スレッドプールからリクエストを処理するスレッドを割り当てる。使用できる内部スレッドには限りがある。この補助スレッド群をワーカーグループと呼ぶ。
  6. イベントループはブロックの要求を追跡し、ブロッキングタスクが処理されるとそれをキューに入れる。こうしてノンブロッキングとしての構造を維持している。

Node.jsは使用するスレッドの数が少ないので、使用するリソースやメモリも少なくなり、結果としてタスクの実行が速くなります。つまり、そのような点では、シングルスレッドアーキテクチャはマルチスレッドアーキテクチャと同等と言えます。データ集約的なタスクを処理するには、Javaのようなマルチスレッド言語を使う方がはるかに理にかなっていますが、リアルタイムアプリケーションにはNode.jsが有用です。

Node.jsの特徴

Node.jsはここ数年で急速に成長しています。これは、Node.jsの膨大な機能によるものです。例えば、以下のような特徴があります。

  1. 簡単:Node.jsは簡単に使い始めることができます。ウェブ開発初心者でも取っ掛かりやすい選択肢です。多くの解説記事や大規模なコミュニティがあります。
  2. スケーラブル:アプリケーションに柔軟なスケーラビリティが確保できます。シングルスレッドであるNode.jsは、高いスループットで膨大な数の同時接続を処理できます。
  3. スピード:ノンブロッキングのスレッド実行により、Node.jsは高速で効率的です。
  4. パッケージ:膨大なオープンソースのNode.jsパッケージが利用可能で、作業の簡素化が可能です。現在、NPMエコシステムには100万以上のパッケージがあります。
  5. 強力なバックエンド:Node.jsはCとC++で書かれているため、スピードが速く、ネットワークサポートなどの機能が追加されています。
  6. マルチプラットフォーム:クロスプラットフォームのサポートにより、Node.jsを使用して、SaaSウェブサイト、PCアプリ、さらにはモバイルアプリを作成することができます。
  7. 保守性:Node.jsは、フロントエンドとバックエンドの両方をJavaScriptで単一言語として管理できるため、開発者にとって扱うのが容易です。

市場規模

過去20年間でウェブは大きな成長を遂げており、Node.jsの成長も例外ではありません。W3Techsによると、Node.jsはサイトの1.2%で使用されているとのことです。これは、インターネット全体で2,000万以上のサイトに相当します。

Node.jsは何百万もの企業にも選ばれています。Node.jsを使用する人気のサイトをいくつかご紹介します。

  • Twitter
  • Spotify
  • eBay
  • Reddit
  • LinkedIn
  • Godaddy

Node.jsのアプリケーション

Node.jsのアプリケーション
Node.jsのアプリケーション

Node.jsは様々なアプリケーションに使用されています。Node.jsが強さを発揮するケースが以下の通りです。

  1. リアルタイムのチャット:シングルスレッドで非同期のため、Node.jsはリアルタイムの通信処理に適しています。簡単に拡張でき、チャットボットを構築する際によく使用されます。Node.jsはまた、複数人チャットやプッシュ通知のような追加チャット機能を簡単に構築できます。
  2. モノのインターネットIoTアプリケーションは通常、複数のセンサーで構成され、小さなデータの塊を頻繁に送信するため、大量のリクエストになる可能性があります。Node.jsは、このような同時リクエストを素早く処理することができるので優れた選択肢です。
  3. データストリーミング:Netflixなどの企業が、ストリーミングにNode.jsを使用しています。これは主にNode.jsが軽量で高速であることに加え、Node.jsがネイティブのストリーミングAPIを提供しているためです。これにより、ユーザーは互いにリクエストをパイピング(pipe)でやり取りすることができ、その結果、データが最終的な宛先に直接ストリーミングされます。
  4. 複雑なシングルページアプリケーション(SPA):SPAでは、アプリケーション全体が1つのページに読み込まれます。これは通常、特定のコンポーネントに対してバックグラウンドでいくつかのリクエストが行われることを意味します。Node.jsのイベントループは、ノンブロッキング方式でリクエストを処理するため、このような状況で力を発揮します。
  5. REST APIベースのアプリケーション:JavaScriptは、サイトのフロントエンドとバックエンドの両方で使用されます。したがって、サーバーはNode.jsを使ってREST API経由でフロントエンドと簡単に通信することができます。Node.jsは、Express.jsやKoaのようなパッケージも提供しており、ウェブアプリケーションの構築がさらに捗ります。

Node.jsはプログラミング言語なのか

一言で言えば、違います

Node.jsはプログラミング言語ではありません。むしろ、ブラウザの外でJavaScriptを実行するための実行環境です。

Node.jsはフレームワーク(ソフトウェアアプリケーションを開発するためのプラットフォーム)でもありません。Node.jsのランタイムは、プログラミング言語(この場合はJavaScript)の上に構築され、フレームワーク自体の実行を助けるものです。

まとめると、Node.jsはプログラミング言語でもフレームワークでもなく、それらのための環境です。

Node.jsはフロントエンドかバックエンドか

開発者の間でよくある誤解は、Node.jsはバックエンドフレームワークであり、サーバーを構築するためだけに使われるというものです。Node.jsはフロントエンドでもバックエンドでも使用できます。

Node.jsのフレームワークが柔軟でスケーラブルなバックエンドを構築する開発者に人気のある理由の1つは、イベント駆動型でノンブロッキングであることです。しかし、フロントエンドの開発者であっても、Node.jsのこのような利点をはっきりと実感することができます。

Node.jsがバックエンドとフロントエンドの両方で機能する理由は以下の通りです。

  1. 再利用性:JavaScriptは、Express.jsやMeteor.jsのようなフレームワークの助けを借りて、バックエンドとフロントエンドの両方で使用できます。MERNのような人気のスタックでは、Express.jsをバックエンド(Node.jsフレームワーク)として使用しています。フロントエンドとバックエンドの間で複数のコンポーネントを再利用することも可能です。
  2. 生産性と開発者の効率:複数言語間のコンテキストスイッチの削減により、開発者の時間を大幅に節約できる。バックエンドとフロントエンドの両方でJavaScriptを使用することで、多くのツールが共通化されるため、効率が向上します。
  3. 巨大なコミュニティ:開発サイクルのスピードアップには、活発なオンラインコミュニティが欠かせません。問題に行き詰まったときでも、誰かがすでに解決し、Stack Overflowで解決策を共有している可能性が高いです。Node.jsでは、そのコミュニティを大いに活用することができます。

Node.jsの利用を開始する

Node.jsをどこから始めればいいのかと圧倒されてしまうかもしれません。しかし幸いなことに、Node.jsは簡単にインストールして試してみることができます。

Node.jsのインストール方法

すでにNode.jsがインストールされている場合は、このセクションを飛ばして進んでください。

macOSの場合

MacでBashを使う

curl "https://nodejs.org/dist/latest/node-${VERSION:-$(wget -qO- https://nodejs.org/dist/latest/ | sed -nE 's|.*>node-(.*).pkg.*|1|p')}.pkg" > "$HOME/Downloads/node-latest.pkg" && sudo installer -store -pkg "$HOME/Downloads/node-latest.pkg" -target "/"

MacでHomebrewを使う

brew install node

Windowsの場合

nodejs.orgのウェブサイトから直接Windowsインストーラをダウンロードしてください。

Linuxの場合

Ubuntu 18.04+では、以下のコマンドを使用してNodeをインストールできます。

sudo apt update
sudo apt install nodejs

インストールされているNode.jsのバージョンの確認

前のセクションでは、Nodeのインストールに成功しました。インストールされたバージョンをチェックして、それを確認しましょう。ターミナルで以下のコマンドを実行することができます。

node -v

versionと記述することでも確認できます。

node --version

このような出力が表示されるはずです。バージョン番号は異なるかもしれん。

v14.16.0

NPMとは

NPMはNode.jsのパッケージエコシステムです。オープンソースライブラリとしては世界最大のエコシステムで、100万を超えるパッケージがあり、その数は今もなお増え続けています。NPMは無料で使用でき、何千人ものオープンソース開発者が日々貢献しています。

NPMにはコマンドラインユーティリティが付属しています。NPMのウェブサイトにアクセスして必要なパッケージを検索し、コマンドひとつでインストールできます。また、このコマンドラインユーティリティを使って、パッケージのバージョンを管理したり、依存関係を確認したり、プロジェクトにカスタムスクリプトを設定することもできます。NPMはNode.jsコミュニティに欠かせない存在です。Node.jsが多くの開発者を惹きつけているのは、その優れたパッケージサポートによるところが大きいでしょう。

CLIによるNPMパッケージのインストール

Node.jsをインストールすると、NPMも一緒に自動でインストールされます。前のセクションでNode.jsのインストール方法を説明したので、NPMでパッケージをインストールするコマンドを見てみましょう。

npm install <package-name>

とても簡単です。複数のパッケージを一度にインストールすることもできます。

npm install <pkg-1> <pkg-2> <pkg-3>

グローバルなコンテキストでパッケージをインストールしたい場合は、-g(global)を指定することもできます。これにより、マシンのあらゆる場所でパッケージを使用できるようになります。

アプリケーションを初期化すると、NPMは自動的にすべてのNPMパッケージからなるpackage.jsonファイルを作成します。ここで、バージョン、依存関係、カスタムスクリプトを指定できます。

NPMユーティリティには、publishauditrunなど、いくつものコマンドがあります。これらの使い方は、npm helpコマンドで確認できます。

Nodeとnpmのバージョン
Nodeとnpmのバージョン

人気のあるパッケージ

現在、Node.jsで人気のパッケージをご紹介します。

  • Express:Express.jsまたは単にExpressは、Node.jsのためのSinatraから着想を得たウェブ開発フレームワークであり、世の中に出回っているNode.jsアプリケーションの大半のデファクトスタンダードです。
  • MongoDB:MongoDBの公式ドライバです。Node.jsでのMongoDBオブジェクトデータベースのAPIが利用可能になります。
  • Socket.io:リアルタイム、双方向、イベントベースの通信を可能にします。
  • Lodash:配列、数値、オブジェクト、文字列などを扱う手間を省き、JavaScriptの扱いを簡単にします。
  • Moment:日付の解析、検証、操作、書式設定のためのJavaScript日付ライブラリです。
  • Commander.js:node.jsのコマンドラインインターフェースで作業したりビルドしたりするのに必要なものすべて揃っています。
  • Forever:指定したスクリプトが継続的に(つまり永遠に)実行されるようにするためのシンプルなCLIツールです。予期せぬ障害に直面しても、Node.jsプロセスを稼働させ続けることができます。
  • Async:非同期JavaScriptを扱うための、わかりやすく強力な関数を提供するユーティリティモジュールです。
  • RedisRedisデータベースの統合をサポートするクライアントライブラリです。
  • Mocha:Node.jsとブラウザ用のクリーンで柔軟なJavaScriptテストフレームワークです。
  • Passport:Node.jsでのシンプルな認証実装を実現します。Passportの唯一の目的はリクエストを認証することです。

Node.jsのHello World

基本的な”Hello World”プログラムから始めましょう。Node.jsでサーバーを作成し、サーバーからのリクエストに対して”Hello World”の出力を返すようにします。好みのテキストエディタをご用意ください。

テキストエディタを開いたら、そこに”Hello World”プログラムに使うコードを記述します。

// server.js
const http = require('http');

const hostname = '127.0.0.1';
const port = 3000;

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World! Welcome to Node.js');
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

このファイルを`server.js`という名前で保存します。次にターミナルに移動し、コマンドを使ってサーバーを起動します。

node server.js

これでサーバーが起動します。出力を確認するには、ブラウザでhttp://localhost:3000を開いてください。次のようなメッセージが表示されるはずです。

Hello World! Welcome to Node.js

Hello Worldサーバーの説明

Node.jsには”HTTP”と呼ばれる組み込みモジュールがあり、Node.jsがHTTP(HyperText Transfer Protocol)でデータを転送できるようになっています。

上のコードでは、まずhttpモジュールをプログラムに読み込みます。次に、createServerメソッドを使ってリクエストを受け付け、ステータスコード付きのレスポンスを返します。最後に指定のポートでリッスンします。

Node.jsで最初のサーバーを作成することができました。次のセクションでは、Expressフレームワークを使ってサーバーを作成する方法をご紹介します。

Expressを使ったサーバーの作成

まず、サーバーとは何かについて説明します。サーバーは、そのソフトウェア(最も一般的なのはApacheまたはNginx)を通してクライアントのリクエストを受け取り、必要な一連のタスクを実行し、最後にクライアントに応答を返す役割を担います。Expressは、Nodeでサーバーを作成するのに便利なフレームワークです。

Express.jsは最小限の設定で使うことのできる柔軟なNode.jsウェブアプリケーションフレームワークで、ウェブ、モバイルアプリケーションの機能が豊富に利用できます。アプリケーションにルートテーブルを追加したり、ミドルウェアを設定したりすることが可能です。以下のコマンドでExpressをインストールできます。

npm install express --save

前のセクションでは、内蔵のhttpユーティリティを使ってサーバーを作成しました。それでは、Express.jsを使って”Hello World”サーバーを作ってみましょう。

テキストエディタを開き、以下のコードを記述してください。


// server-express.js
const express = require('express')
const app = express() // アプリの初期化
const port = 3000

// GETコールバック関数がレスポンスメッセージを返す
app.get('/', (req, res) => {
res.send('Hello World! Welcome to Node.js')
})

app.listen(port, () => {
console.log(`Server listening at http://localhost:${port}`)
})

次に、以下のコマンドでサーバーを実行しあmす。

node server-express.js

ブラウザでhttp://localhost:3000を開いて、”Hello World”の出力を確認できます。

まとめ

一言で言えば、Node.jsは、複数の同時リクエストをサポートする必要がある大規模アプリケーションの構築に使用できる、人気のプログラミング環境です。シングルスレッド、ノンブロッキングI/Oなので、リアルタイムアプリケーションにもデータストリーミングアプリケーションにも活用できます。

さらに、Node.jsの開発者コミュニティは大規模で、世界最大のオープンソースパッケージリポジトリであるNPMには、現在100万以上のパッケージが登録されています。

Node.jsは簡単に使い始めることができます。今回はNode.jsのインストールとサーバーの作成方法についてご説明しました。あとはご自身のスタックでNode.jsをどのように使用し、実装するかを考えるだけです。nodejs.devにあるNode.jsの公式ドキュメントにアクセスして知識を深めることもできます。