目次

まえがき

本書のターゲット
本書のバックグラウンド
底本について
サンプルコードについて
【参考】:macでのnodebrewのインストール

第1章 Node.jsの全体像

1.1 サーバーサイドのJavaScript実行環境
1.2 V8 JavaScript Engine
1.3 Node.jsで使えるJavaScriptの文法
1.4 libuv
1.5 node-core(JavaScript API)
1.6 Node.jsのリリースサイクル
1.7 まとめ

第2章 npm(Node Package Manager)

2.1 package.json
2.2 package-lock.json
2.3 npmの設定
2.4 npx
2.5 npmパッケージの選定
2.6 Yarn
2.7 npmとyarnのどちらを使うのか

第3章 サーバーとしてのNode.js

3.1 シングルプロセスとシングルスレッド
3.2 クラスタリング
3.3 プロセスマネージャー
3.4 まとめ

第4章 イベントループ

4.1 イベントキュー
4.2 イベントループ
4.3 ブラウザーとキューとスレッド
4.4 まとめ

第5章 非同期プログラミング(コールバック)

5.1 例外で知る同期と非同期の違い
5.2 まとめ

第6章 コールバック地獄の解消

6.1 関数分割
6.2 Promise
6.3 co
6.4 async/await
6.5 それぞれの方法におけるエラーの捕捉
6.6 Promise(エラー系)
6.7 co(エラー系)
6.8 async/await(エラー系)
6.9 まとめ

第7章 Stream

7.1 Streamを制するものは、Node.jsを制す
7.2 fs.createReadStream()
7.3 node-coreのAPIパターンを使い分けよう
7.4 EventEmitter
7.5 ES2018 Async Iteration(for await...of)
7.6 highWaterMark
7.7 Streamは難易度が高い?
7.8 まとめ

第8章 AltJSとTypeScriptを使った開発

8.1 AltJS(代替JavaScript言語)とは
8.2 AltJSの種類
8.3 TypeScript
8.4 TypeScriptを使ったNode.jsの開発
8.5 まとめ

第9章 コーディングガイドラインとESLint

9.1 Airbnb JavaScript Style Guide
9.2 JavaScript Standard Style
9.3 ESLint
9.4 ESLintとコーディングガイドラインの連携
9.5 コードを自動フォーマットするPrettier
9.6 まとめ

第10章 Node.jsとセキュリティ

10.1 セキュリティの基礎知識を習得しよう
10.2 Node.jsのアップデート
10.3 サーバー自身のセキュリティ対策
10.4 Expressのベスト・プラクティスに学ぼう
10.5 Node.jsのセキュリティ・チェックリスト
10.6 まとめ

第11章 Node.jsのコアには、どのようなモジュールがあるのか

11.1 公式ドキュメントではStabilityに注意しよう
11.2 Assertion Testing
11.3 Async Hooks
11.4 Buffer
11.5 C++ Addons / C・C++ Addons with N-API
11.6 Child Process
11.7 Cluster
11.8 Command Line Options
11.9 Console
11.10 Crypto
11.11 Debugger / Inspector
11.12 Deprecated APIs
11.13 DNS
11.14 Domain
11.15 ECMAScript Modules
11.16 Errors
11.17 Events
11.18 File System
11.19 Globals
11.20 HTTP / HTTPS
11.21 HTTP/2
11.22 Internationalization
11.23 Modules
11.24 Net
11.25 OS
11.26 Path
11.27 Performance Timing API
11.28 Policies
11.29 Process
11.30 Punycode
11.31 Query Strings
11.32 Readline
11.33 REPL
11.34 Report(Diagnostic Report)
11.35 Stream
11.36 String Decoder
11.37 Timers
11.38 TLS/SSL
11.39 Trace Events
11.40 TTY
11.41 UDP/Datagram
11.42 URL
11.43 Utilities(Util)
11.44 V8
11.45 VM (Executing JavaScript)
11.46 WASI(WebAssembly System Interface)
11.47 Worker Threads
11.48 Zlib

第12章 JavaScript & Node.js Tips集

12.1 Strict モード
12.2 varとletの違い
12.3 ログを出力する場所について
12.4 開発環境と本番環境のconfigを切り替える
12.5 validatorを使った入力チェック
12.6 数値の仕様について
12.7 nullとundefinedの違い
12.8 JavaScriptの暗黙的型変換
12.9 JavaScriptのthis問題
12.10 Socket.IOの負荷分散
12.11 グラブルの安定稼働を支えるNode.js
12.12 PLAIDが5年間で12万行書いてわかったこと
12.13 Node.jsとFaaS(Function as a Service)
12.14 Node.jsのフレームワークはどれを使えば良いのか?
12.15 Node.jsでユニットテスト
12.16 C10K問題を解消するNode.js

付録A Node.jsの習得に役立つ情報を得るには

A.1 (書籍)Node.jsデザインパターン 第2版
A.2 イベント
A.3 (ブログ)エンジニアブログ
A.4 (ポッドキャスト)mozaic.fm
A.5 ウェブ

付録B ES2015(ES6)

B.1 Arrow Functions
B.2 Promises
B.3 Generators
B.4 let and const
B.5 Classes
B.6 import/export
B.7 Template Literals
B.8 Default parameters
B.9 The spread operator
B.10 Destructuring assignments
B.11 Enhanced Object Literals
B.12 For-of loop
B.13 Map and Set
B.14 New String methods
B.15 New Object methods

付録C ES2016

C.1 Array.prototype.includes()
C.2 Exponentiation Operator

付録D ES2017

D.1 String padding
D.2 Object.values()
D.3 Object.entries()
D.4 Object.getOwnPropertyDescriptors()
D.5 Trailing commas
D.6 Async functions
D.7 Shared Memory and Atomics

付録E ES2018

E.1 Rest parameters
E.2 Spread Properties
E.3 Asynchronous iteration
E.4 Promise.prototype.finally()
E.5 Regular Expression improvements

付録F ES2019

F.1 Array.prototype.flat()
F.2 Array.prototype.flatMap()
F.3 Optional catch binding
F.4 Object.fromEntries()
F.5 String.prototype.trimStart()
F.6 String.prototype.trimEnd()
F.7 Symbol.prototype.description
F.8 JSONにおける\u2028と\u2029問題の改善
F.9 JSONにおけるサロゲート文字列のエンコード問題の改善
F.10 Function.prototype.toString()
F.11 ES2015以降のJavaScriptの学び方

付録G Node.js v13とv14について

G.1 Node.js v13
G.2 Node.js v14

あとがき

主要参考文献

まえがき

 本書はNode.jsの採用をきっかけにして、同期プログラミングから非同期プログラミングの世界へと足を踏み入れた筆者の、学習をまとめた学習記録です。

 The Node Way(Node流)を身に着けていく中で、筆者がスキルアップのために覚えた内容を振り返りながら一冊の本にまとめました。

 ・新しいJavaScriptでは何が変わったのか?

 ・コールバック地獄の解消

 ・非同期プログラミングにおける例外の捕捉

 ・クラスター化によるWEBサーバー運用

 ・・・をはじめ、Node.jsには学びのポイントがたくさんあります。

 本書には主に筆者が、独学や実戦で学んだ内容が記載してあります。日記を読むような感覚で、気軽に楽んでいただけましたら幸いです。

本書のターゲット

 ・Node.jsについて理解を深め、ステップアップとして中級者を目指したい方

 ・非同期プログラミングや、シングルスレッドという言葉に馴染みがない方

 ・Node.jsそのものに対する技術的な興味がある方

 本書はNode.js、およびその周辺環境に対する理解度を向上することを目的としています。Node.jsの入門書の次に読む、副読本のような形でお楽しみください。

 なお入門書の次に読むことを想定しているため、環境構築の章を専用に設けておりません。そのため、入門書などで構築した環境をそのままお使いください。

本書のバックグラウンド

 筆者が主にNode.jsで開発していたのは数年前のことですが、今回はその知識をアップデートしながら本書を執筆いたしました。なお筆者は、Socket.IOのウェブソケットシステムでNode.jsを活用しております。その過程で得た、Node.jsそのものに対する知識を本書で執筆しました。

底本について

 本書は技術書典7で頒布した「Node.js中級者を目指す」の加筆修正版です。印刷〆切の都合で書けなかった内容を追記し、また細かな修正を行ないました。

サンプルコードについて

 サンプルコードはGitHubにあります。

 ・https://github.com/konosumi/techbook-levelupnodejs-sample

 本書におけるJavaScriptの動作確認は、執筆を開始した時点の最新版(Node.js v12.6.0)で行なっております。なお筆者は、macのnodebrewを利用いたしました。

【参考】:macでのnodebrewのインストール

# Homebrew で nodebrew をインストールします。

$ brew install nodebrew


# インストール可能な Node.js の一覧を表示します。

$ nodebrew ls-remote


# LTSであるv12のNode.js(2020/01/21時点)をインストールします。

# なお単なる nodebrew install v12.14.1 でも問題ありません(遅いですが)

$ nodebrew install-binary v12.14.1


# インストール後に使用を宣言すると有効になります

# これは nodebrew が Node.js のバージョン切り替え機能を有しているためです

$ nodebrew use v12.14.1


# nodebrewでインストールしたnodeのパスを通す

$ vim ~/.bash_profile

# 以下がなければ追加する

> # Node.js

> export PATH=$HOME/.nodebrew/current/bin:$PATH


$ source ~/.bash_profile

$ node --version

v12.14.1

第1章 Node.jsの全体像

 個々の項目を学ぶ前に、まずはNode.jsの全体像から掴んでいきます。

 さあ、学習の始まりです!

1.1 サーバーサイドのJavaScript実行環境

 Node.jsを一言で表現するならば、サーバーサイドのJavaScript実行環境です。2009年から開発がスタートし、カリフォルニアで生まれ育ったライアン・ダールによって開発されました。

 次の特徴があります。

 1.非同期型

 2.イベント駆動

Node はスケーラブルなネットワークアプリケーションを構築するために設計された、非同期型のイベント駆動のJavaScript環境です。

https://nodejs.org/ja/about/ より

 Node.jsの主な構成要素を次の図に示します。

図1.1: Node.jsの全体像

 この図は「Node.jsデザインパターン1」を参考に作成いたしました。「Node.jsデザインパターン」は中級者以上のウェブ開発者を対象とした書籍で、Node.jsを詳しく知る上でとても参考になる書籍です。

1.2 V8 JavaScript Engine

 Node.jsではアプリケーションプログラムをJavaScriptで記述します。その実行を担っているのが、「V8 JavaScript Engine」です。

V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.It is used in Chrome and in Node.js, among others.

It implements ECMAScript and WebAssembly, and runs on Windows 7 or later, macOS 10.12+, and Linux systems that use x64, IA-32, ARM, or MIPS processors.

V8 can run standalone, or can be embedded into any C++ application.

https://v8.dev/ より

 V8はGoogleが開発しているオープンソースのJavaScript実行エンジンです。V8はNode.jsに限らず、Google Chromeでも採用されています。サーバーサイドでもブラウザーサイドでも活躍する、とても馴染みの深い存在です。

 なおブラウザーにより、JavaScriptの実行エンジンは異なります。普段の開発で実行エンジンの違いを意識することは多くないかもしれませんが、フロントエンドエンジニアであれば知っておくことをオススメします。

 ・Firefox: SpiderMonkey

 ・Safari: JavaScriptCore

 ・Microsoft Edge: Chakra / V8

Firefox: SpiderMonkey

SpiderMonkeyは、C/C++で書かれたJavaScriptエンジンです。Firefoxを含む、Mozillaの複数の製品で使用されており、MPL2ライセンスの下で利用できます。

https://developer.mozilla.org/ja/docs/Mozilla/Projects/SpiderMonkey より

Safari: JavaScriptCore

JavaScriptCore is the built-in JavaScript engine for WebKit. It currently implements ECMAScript as in ECMA-262 specification.

https://trac.webkit.org/wiki/JavaScriptCore より

 SafariはWebKitと呼ばれるWeb browser engineで動きますが、WebKitはJavaScriptCoreを含みます。またJavaScriptCoreはフレームワークとしても提供されており、Objective-CやSwiftを使ってiOSアプリでも動きます。

Microsoft Edge: Chakra / V8

 Microsoft EdgeはChakraと呼ばれるJavaScriptエンジンを採用していました。しかしChromium(Blink + V8)を採用することを決断し、Chromiumを搭載したEdgeが2020年に登場しました。

 すでに正式リリースされていますが、日本では確定申告などへの影響を考慮して自動アップデートの提供は遅れています。

「Microsoft Edge」はこれまで独自のレンダリングエンジンとJavaScriptエンジン(「EdgeHtml」+「Chakra」)を採用してきましたが、「Google Chrome」などのベースとなっている「Chromium」に比べ、Web標準技術の実装や機能面で後塵を拝してきました。同社はバッテリー駆動時間の長さなどをアピールして普及に努めてきたものの、「Internet Explorer」時代のシェアを取り戻すことはできず、とうとう「Chromium」(「Blink」+「V8」)を採用することを決意したようです。

https://forest.watch.impress.co.jp/docs/news/1157163.html より

V8 JavaScript Engineのバージョンについて

 Node.jsに「10.x」や「8.x」といったバージョンがあるように、V8にもバージョンがあります。nodeが採用しているV8のバージョンは、Node.jsのバージョンによって決まります。

 本書の執筆開始時点(Node.js 12.6.0)では、V8 7.5が使われていることがリリース一覧を見るとわかります。

図1.2: https://nodejs.org/ja/download/releases/ より

 V8のバージョンは重要です。なぜならNode.jsでES2015(ES6)をはじめとする新しいJavaScriptの文法が使えるのは、V8のバージョンアップにNode.jsが追従しているからです。

Node.jsはV8のモダンなバージョンに対して作られています。V8 を最新の状態に保つことでJavaScript ECMA-262の新機能を開発者にすみやかに提供し、継続的なパフォーマンスと安定性の向上を保証しています。

https://nodejs.org/ja/docs/es6/ より

1.3 Node.jsで使えるJavaScriptの文法

 JavaScriptは毎年のように進化を続けています。この進化には名前がつけられており、ES2015/ES2016/ES2017・・・と呼ばれます。

 なお場所によってES6やES7と呼ばれることもあります。6や7はEdition番号ですが、本来は年号つきの仕様書名が正式名称です。

 ・ECMAScript 1st Edition (ES) 1997年6月

 ・ECMAScript 2nd Edition (ES2) 1998年6月

 ・ECMAScript 3rd Edition (ES3) 1999年12月

 ・ECMAScript 4th Edition (ES4) (放棄)

 ・ECMAScript 5th Edition (ES5) 2009年12月

 ・ECMAScript 5.1th Edition (ES5.1) 2011年6月

 ・ECMAScript 2015 (ES2015/ES6) 2015年6月

 ・ECMAScript 2016 (ES2016/ES7) 2016年6月

 ・ECMAScript 2017 (ES2017/ES8) 2017年6月

 ・ECMAScript 2018 (ES2018/ES9) 2018年6月

 ・ECMAScript 2019 (ES2019/ES10) 2019年6月

 ESとはECMAScriptの略称で、JavaScriptの標準規格のことです。国際的な標準化団体であるEcma Internationalにて、ECMA-262と呼ばれる規格番号で標準化されます。

ECMAScriptとEcma Internationalとは?

Ecma International(正式名:欧州電子計算機工業会; European Computer Manufacturers Association)は、コンピュータ・ハードウェアや通信、プログラム言語の標準規格を策定する非営利組織です。

ウェブの世界では、JavaScript言語の中核的規格であるECMA-262規格(別名:ECMAScript)を維持・管理する組織として有名です。

https://developer.mozilla.org/ja/docs/Glossary/ECMA より

TC39と放棄されたES4

 Ecma TC39とは、ECMAScriptを策定してる専門委員会のことです。TC39にはJavaScriptおよびブラウザーに関わる企業が、多く参加しています。

 放棄されたES4では、Netscape Communications社やマイクロソフト社をはじめとする意見が対立し、最終的に議論が打ち切りとなってしまいました。

 このような混乱があったため、ES3からES5への道のりは長い時間を要しています。

MDNのブラウザー実装状況

 Node.jsで使える新しい文法は、MDN2のブラウザー実装状況で確認できます。

図1.3: MDNのブラウザー実装状況には、右端にNode.jsが掲載されている

 一覧でみたい場合は、有志によって運営されている対応表も参考になります。

 ・Node.js ECMAScript compatibility tables

  ─https://node.green/

 ・ECMAScript compatibility tables

  ─https://kangax.github.io/compat-table/es6/

 Node.jsをバージョンアップすれば基本的にV8のバージョンも上がるため、より新しい文法が使いたければNode.jsのバージョンを最新に保つ必要があると覚えておきましょう。

CommonJSとrequire()

 Node.jsのプログラムでは、次のようなrequire()を多く見かけます。

リスト1.1: require()を使ったモジュールの読み込み

 1: const http = require('http');

 require()はCommonJSという仕様を基本にしており、Node.jsに追加された記法です。またBrowserifyにも採用された実績があり、クライアントサイドでも活用例があります。

 CommonJSとはJavaScriptを使い、サーバーサイドやコマンドラインツールをはじめとする、さまざまなアプリを開発するための標準的なAPIを定めることを目標としたプロジェクトです。

モジュールの歩み

Node.jsとCommonJSは2009年に開発され、大半のnpmパッケージでCommonJSが使われています。

Browserifyは2011年にリリースされた、すべての必要なオブジェクトをひとつのJavaScriptファイルにまとめるツールです。クライアントサイドのJavaScriptでnpmパッケージをrequireで読み込ませるために、CommonJSを採用しました。

https://www.webprofessional.jp/javascript-modules-bundling-transpiling/ より

 require()はモジュールをインポートする側の記法ですが、モジュールをエクスポートする記法もあります。

リスト1.2: CommonJSをベースにしたmodule.exports

 1: module.exports = function hello() {
   2:   console.log('Hello world!');
   3: };
   4: module.exports = class Hello { /* ... */ }

ECMAScript Modules

 モジュールのエクスポートにはECMAScriptを使った記法もあり、js-primer(JavaScript入門書)の執筆でも有名なazu(@azu_re)さんのGitHub Gistをみると、両者の感覚的な違いがよくわかります。

 ・ES6 modulesでexportしたい / CommonJS modulesでexportしたい

 ・https://gist.github.com/azu/09ee80c1a3127737000a

 ただしECMAScriptのModules機能を標準のNode.jsで使うためには、いくつかの注意事項があります。主な注意点としてコマンドへの「--experimental-modules3」の追加と、基本的にJSファイルの拡張子を「.mjs」とします。

 または最も近い親のpackage.jsonに「"type": "module"」を追加すれば、「.js」でも利用可能です。

ECMAScript Modules

The --experimental-modules flag can be used to enable support for ECMAScript modules (ES modules).

 

● Files ending in .mjs.

● Files ending in .js, or extensionless files, when the nearest parent package.json file contains a top-level field "type" with a value of "module".

● Strings passed in as an argument to --eval or --print, or piped to node via STDIN, with the flag --input-type=module.

 

https://nodejs.org/docs/latest-v12.x/api/esm.html より

 なお詳しい内容が知りたい方は、hiroppy(@about_hiroppy)さんの記事が参考になります。hiroppyさんはNode.jsとwebpackのコミッターです。

 ・Node.jsの新しいモジュール方式の実験的導入

 ・https://blog.hiroppy.me/entry/nodejs-experimental-modules

CommonJSを勉強するべきかどうか

 ECMAScript Modulesを使うためにはわざわざオプションを有効にする必要があるため、Node.jsではCommonJSを重点的に勉強する必要があるように感じられます。しかしながら状況は時代とともに変化しており、一概にそうとは言い切れません。

Forget CommonJS. It's dead. We are server side JavaScript.

https://github.com/nodejs/node-v0.x-archive/issues/5132#issuecomment-15432598 より

 前の発言を読むと、Node.jsはCommonJSを離れようとしていることがわかります。

1.4 libuv

 Node.jsには次の特徴がありますが、それを支えているのがlibuvです。

 ・ノンブロッキングI/O

 ・イベント駆動プログラミング

 ・非同期プログラミング

 libuvはC言語で作成されたライブラリーで、低レイヤーのノンブロッキングI/Oをプラットフォーム(windows, mac, unix...)間の互換性を保ちつつ提供します。

 またイベントループ用のイベントキューや、ノンブロッキングI/Oによる非同期I/Oなども提供します。Nodeのコア開発チームによって開発され、Node.jsの強みや特徴を下支えしている存在がlibuvです。

libuv is a multi-platform support library with a focus on asynchronous I/O.

It was primarily developed for use by Node.js, but it’s also used by Luvit, Julia, pyuv, and others.

http://docs.libuv.org/en/v1.x/ より

libev

 Node.jsでは、かつてイベント駆動のI/Oライブラリーとしてlibevが採用されていました。しかしlibevは、Unix系OSには対応していたものの、Windowsに対応していないという欠点があります。

 そのためnode-v0.9より、libevはlivubに置き換えられたという、歴史的経緯があります。

The node.js project began in 2009 as a JavaScript environment decoupled from the browser.Using Google’s V8 and Marc Lehmann’s libev, node.js combined a model of I/O – evented – with a language that was well suited to the style of programming;

due to the way it had been shaped by browsers. As node.js grew in popularity, it was important to make it work on Windows, but libev ran only on Unix. The Windows equivalent of kernel event notification mechanisms like kqueue or (e)poll is IOCP. libuv was an abstraction around libev or IOCP depending on the platform, providing users an API based on libev. In the node-v0.9.0 version of libuv libev was removed.

https://nikhilm.github.io/uvbook/introduction.html より

試し読みはここまでです。
この続きは、製品版でお楽しみください。