前回に引き続き、『サーバーサイドJavaScript Node.js入門』「8.1.3 ストリームの接続」p.97のサンプルもreadableイベントに合わせてみます。使用したNode.jsのバージョンはv0.10.12です。
まずは旧バージョン。
『サーバーサイドJavaScript Node.js入門』p.97のサンプル
var path = require('path'), fs = require('fs'); var outputFilePath = path.join(__dirname, 'write.txt'); var writeStream = fs.createWriteStream(outputFilePath); var inputFilePath = path.join(__dirname, 'test.txt'); var readStream = fs.createReadStream(inputFilePath); writeStream.on('error', function(err) { console.log('An error occured'); console.log(err); }); writeStream.on('close', function() { console.log('writable stream closed'); }); writeStream.on('drain', function() { console.log('resume writing'); readStream.resume(); }); writeStream.on('drain', function() { console.log('resume writing'); readStream.resume(); }); readStream.on('data', function(data) { console.log('>> a data event occured.'); if (writeStream.write(data) === false) { console.log('pause writing'); readStream.pause(); } }); readStream.on('end', function() { console.log('read end'); }); readStream.on('error', function(err) { console.log('An error occured'); console.log(err); });
そしてこれをreadableイベントを使用するように変更。
v0.10系に合わせた例
var path = require('path'), fs = require('fs'); var outputFilePath = path.join(__dirname, 'write.txt'); var writeStream = fs.createWriteStream(outputFilePath); var inputFilePath = path.join(__dirname, 'test.txt'); var readStream = fs.createReadStream(inputFilePath); writeStream.on('error', function(err) { console.log('An error occured'); console.log(err); }); writeStream.on('close', function() { console.log('writable stream closed'); }); writeStream.on('drain', function() { console.log('drain'); }); readStream.on('readable', function() { console.log('readable'); if (writeStream.write(this.read())) { console.log('wrote'); } else { console.log('write failed'); } }); readStream.on('end', function() { console.log('read end'); }); readStream.on('error', function(err) { console.log('An error occured'); console.log(err); });
実測値は載せませんが、コンソール出力箇所を除いて実行時間を計測すると、修正後のパフォーマンスは若干良くなります。
21〜28行目を見ると分かるように、実際はもはやwriteでfalseをチェックしてpauseする必要もなければ、darinでresume(17〜19行目)をかける必要もありません。というか、pause、resumeしてはいけません。これをやると旧モードに切り替えられてしまいます。
このサンプルは、続くpipeのサンプルへの前フリのようなものみたいですが、pipeを使用する場合と変わらないほどシンプルになってしまいます。この場でpipeを使えなくても、フィルタみたいな処理をしたい場合などで少し楽になりますね。では、pipeがどのように処理しているのかというと、出力出来る機会さえあれば出力するなど何やらガチャガチャやっているようですが(readableでもdrainでも、そしてprocess.nextTickでも読めるデータさえあれば出力するようです)、複数の出力先を扱うことが考慮されていることを除けば概ね同様と言ってよさそうです(_stream_readable.js)。