以下では、JavaScript のブロッキング特性についての簡単な紹介を行います。その過程で、fs のようなさまざまな Node モジュールの探索も行います。
これはコートクリサリスのイマーシブブートキャンプのプレコースを受講する前に、すべての学生が読み込むべき一連の課題、プロジェクト、評価、作業をまとめたものです。
始める前に
- コンピュータに Node.js をインストールする必要があります。Node.js は、ブラウザ上だけではなくコンピュータ上で JavaScript を実行できるようにするプログラムです。それにより、JavaScript を使用してサーバーサイドを制御することができることを意味します。もし初めて Node.js を使うのであれば、Node School をチェックして始めてみてください。
- このチュートリアルはハンズオンなので、自分でコードを書く必要があります。
- ドキュメントに目を通して読み、学ぶことは、ソフトウェアエンジニアにとって非常に重要なスキルです。このチュートリアルを進めながら、Node.js のドキュメントに目を通す練習をしてください。また、自身の Node.js のバージョンと、見ているドキュメントのバージョンに注意してください。
達成目標
- fs の使い方に慣れる。
- fs.readFileSync を使用して、ローカルシステム上のファイルを読み込む。
- 同期およびブロッキングという言葉を使用して、JavaScript の特定の側面を説明する。
バックグラウンド
同期とブロッキング
次の関数を作ってみましょう:
console.log('1');
function hello() {
console.log('hello');
}
console.log('2');
hello();
console.log('3');
出力結果を予想できますか?
答え:
1
2
hello
3
hello が代わりに長時間実行される操作であった場合はどうなりますか?もしデータベースの検索や HTTP リクエストだったらどうなりますか?それらがどのように実装されているか考える必要はありません。この場合、hello が完了するのにもっと長い時間がかかると考えてもらえればよいです。
これはつまり、処理が完了するまで最後の console.log が呼び出されないということでしょうか?はい、JavaScript ではそうなります。これは、JavaScript が一度に 1 つのことしかできないためです(応用的な内容:シングルスレッド)。これは、同期 処理と呼ばれるものです。
同期処理では、何かの処理で時間がかかる場合、その関数はその処理が完了するまで残りのコードの実行を ブロック します。
ブラウザでは、応答しない Web ページの状態にあたります。
サーバー上では、リクエストの処理が停止してしまう状態にあたります。
少しギアを上げていきましょう…
fs の紹介
すべてがグローバルであるブラウザーとは異なり、Node には 2 つのグローバルなものがあります:module オブジェクトと require() 関数です。
後で module は扱うとして、ここでは fs に require() を使ってみましょう:
const fs = require('fs');
console.log(fs);
fs とは何でしょうか?確認する方法として 2 つあります:
- ドキュメントを確認する。
- console.log() を試す!
file 関連のメソッドがたくさんあるので、これが "ファイルシステム" の略だと推測できます。
現在のディレクトリで、次のコマンドを実行しましょう:
echo 'hello world' >> index.js
次に、Node で次の内容を実行しましょう:
const fs = require('fs');
const result = fs.readFileSync('index.js', 'utf8');
console.log(result);
結果はどうなりますか? 'utf8' を含んでいない場合、何が起こるでしょうか? 'utf8' とは何でしょうか?
ブロッキングの振る舞い
上記の例では、ファイルの読み取りが完了するまで console.log が実行されないことに注意してください。巨大なコードの塊になるように、index.js を修正してみてください。それで実行される順序が変わりますか?
いいえ。
これは、fs.readFileSync がその名前が示すとおりに動作するためです。つまり、これは同期メソッドであり、したがってブロッキングを行っています。ファイルがどんなに大きくても、JavaScript は fs.readFileSync が読み込みを完了するまで待機します。
これを通常の JavaScript で確認してみましょう。
高階関数でのブロッキングの振る舞い
ここでは高階関数を作成し、コールバックとして hello を提供しましょう。
console.log('1');
function hello() {
console.log('hello');
};
console.log('2');
function invokeNow(action) {
console.log('3');
action();
}
console.log('4');
invokeNow(hello)
console.log('5');
出力結果を予想できますか?
答え:
1
2
4
3
hello
5
invokeNow(hello) は依然としてブロッキングの振る舞いを示しています。5 を出力する前に、すべての処理が完了するまで待つ必要があります。
チャレンジ
- fs.readFileSync() を使用して、JavaScript のファイル以外を読み込むことはできますか?JSON ファイルまたはテキスト(.txt)ファイルはどうでしょうか?html ファイルはどうでしょうか?それぞれ試してみましょう。
- 'utf8' 以外のオプションとして何がありますか?
- 同期の反対は非同期と呼ばれます。非同期とはどういう意味でしょうか?
- fs.readFile を調べましょう。これは、fs.readFileSync の非同期バージョンです。どのように使うのでしょうか?何が違うのでしょうか?
参考記事
ここでは、いくつかの参考記事(英語)をご紹介します。ご紹介の記事以外にも多くの記事があるので、必要に応じて他の参考記事を探してください。
- Blocking vs non-blocking JavaScript(JavaScript のブロッキングとノンブロッキングの比較について、Node.js 公式ドキュメント)
- What every programmer should know about Synchronous vs. Asynchronous Code(同期と非同期についての解説記事)
Code Chrysalis は日本・東京にあるプログラミングブートキャンプです。3 ヶ月間で強靭なソフトウェアエンジニアになるイマーシブは、オンサイトではもちろんリモートでも受講可能です。
👋 いつでもお気軽にお問い合わせください!
Twitter - YouTube - Instagram - Facebook - LinkedIn