[![](https://www.tech-tech.xyz/wp-content/uploads/2018/10/read-text.jpg)](https://www.tech-tech.xyz/wp-content/uploads/2018/10/read-text.jpg)
まよったらreadFileSyncを使う
--------------------
Node.jsをはじめたばかりで「同期?非同期?」な人は、 とりあえず、**fs.readFileSync**を使うのが無難です。 readFileSyncを使うことでJavaやPython,Rubyなど 一般的な言語のファイル読み込みと同じ挙動になります。 下記はファイルを読み込んで、その内容を表示するスクリプトです。
```javascript
const fs = require('fs');
const msg = fs.readFileSync("hoge.txt", {encoding: "utf-8"});
console.log(msg);
実行すると、ファイルの中身が表示されます。
ほげほげふがふが
Node.js風の書き方readFile
次に非同期処理を生かしたNode.js風の書き方をしてみます。 readFileSyncではなく、fs.readFileを利用してみます。
const fs = require('fs');
let msg = '';
fs.readFile('hoge.txt', 'utf-8', (err, data) => {
// 例外処理
if (err) { throw err; }
msg = data;
console.log(msg);
});
console.log('ファイル読み込み中でも処理が走ります。');
上記のスクリプトを実行すると、環境にもよりますが、 多くの場合、下記のような結果が表示されます。
ファイル実行中でも処理が走ります。
ほげほげふがふが
console.log('ファイル読み込み中でも処理が走ります。')
のところが、先に実行されているのがポイントです。 これは、時間のかかるファイルの読み込みの終了を待たずに 次の処理が実行されるよう非同期にコードを書いたからです。 こちらは、Node.jsの強みを生かしたよりNode.jsらしい書き方です。
ブロッキングI/OとノンブロッキングI/O
上記の結果をもう少し掘り下げると、 ノンブロッキングI/OとブロッキングI/Oというとらえ方ができます。
- fs.readFileSync (ブロッキングI/O)
- fs.readFile (ノンブロッキングI/O)
つまり、 ブロッキングI/Oはファイルの読み込みが完了するまで待ってから、次の処理を実行します。 ノンブロッキングI/Oは読み込みが完了するのを待たず、次の処理を実行します。
readFileSync,readFileのメリットとデメリット
両者のメリットデメリットをまとめと次のようになります。
readFileSync
- メリット: 理解しやすく、コードもわかりやすい
- デメリット: Node.jsのノンブロッキングI/Oの恩恵を得られない
readFile
- メリット: ノンブロッキングI/Oによるパフォーマンスの向上
- デメリット: コードが複雑になって、デバッグしづらい
readFileをpromisify(コールバック関数地獄を軽減)
fs.readFile
のサンプルコードは コールバック関数で読み込み完了後の処理を書きました。 しかし、読み込み後の処理が複雑になると、 コールバック関数の中にコールバック関数、さらにコールバック関数と… なりコードがとても読みにくくなってしまいます。(通称:コールバック関数地獄) これを解決する方法として、Promiseというデザインパターンを利用する方法があります。 そして、node8から、Promiseを簡単に実装できる promisifyという便利ツールが実装されました。 これを使ってfs.readFile
のサンプルコードを書き直すと次のようになります。
const fs = require('fs');
const util = require('util');
const readFile = util.promisfy(fs.readFile);
let msg = '';
readFile('hoge.txt', 'utf-8')
.then((data) => {
// thenの中に完了後の処理を書く
msg = data;
console.log(msg);
})
.catch((err) => {
// catchの中に例外処理を書く
throw err;
});
console.log('ファイル読み込み中でも処理が走ります。');
promise.then(正常処理)
、promise.catch(例外処理)
のような書き方をすることで、 コールバック関数地獄が軽減されます。 とはいえ、今回のような簡単な処理の場合は、 promiseを使った処理は大げさなので、 使いどころを考えるのが重要です。
“`
コメント