今日は、Node の Stream をちゃんと理解したいと思ったので、いくつか試してみた。
stream-handbookを流している。ちょっと、今まで私がやってきた言語と違う雰囲気なので、ゆっくり理解したい。
pipe
Node の Stream は、unix のような pipe が使えるようす。
import * as http from 'http';
import * as fs from 'fs';
var oppressor = require('oppressor');
let server = http.createServer(function (req, res) {
let stream = fs.createReadStream(__dirname + '/server.ts');
stream.pipe(oppressor(req)).pipe(res);
});
server.listen(8000);
これっを実行すると、8000ポートでサーバが起動されて、このファイル自体を結果として返す。その際、oppressor という stream に対応したライブラリで、zip 圧縮をかけている。
Google の開発ツールで見ると、しっかりgzip がかかっているのがわかる。
Readable
stream の Readable の、push メソッドで、Readable オブジェクトにデータを送ることができる。それをstdout にパイプして、出力している。
let Readable = require('stream').Readable;
namespace readable {
let rs = new Readable;
rs.push("hi ");
rs.push("Now I'm in Las Vegas\n");
rs.push(null);
rs.pipe(process.stdout);
}
hi Now I'm in Las Vegas
_read
というメソッドを使うと、パイプ先から必要性があるときのみ、オンデマンドで、コールバックが呼ばれる
import {Readable} from 'stream';
namespace readable02 {
let rs = new Readable;
var c = 65 - 1;
rs._read = function () {
if (c > 'Z'.charCodeAt(0)) rs.push(null);
setTimeout(function() {
rs.push(String.fromCharCode(++c));
}, 100);
};
rs.pipe(process.stdout);
process.on('exit', function () {
console.error('\n _read() called ' + (c - 65) + 'times');
});
process.stdout.on('error', process.exit);
}
$ node readable02.js | head -c4
ABCD
_read() called 4times
ちなみに、タイムアウトを抜かすと、こんな感じになる。
$ node readable02.js | head -c4
ABCD
_read() called 26times
結果は正しいのだが、最後の出力結果がおかしい。これは、どういうことかというと、 _read() はあくまでオンデマンドでコールされるの。最後の、process.stdout.on('error', process.exit);
は、head -c4 で、4つのキャラクターを読んでその後不要になったら、SIGPIPE が発生するので、それを検出して、exit イベントを発生させて、それが、process.on('exit', ...
で検出されてこれが表示される。
ところが、OS から、SIGPIPE が来るまでのタイムラグがあるので、タイマーで待っている状態だ。
おまけ
さて、このプログラムをコンパイルする過程で、謎エラーに悩まされた。
$ tsc -p .
readable02.ts(1,5): error TS2451: Cannot redeclare block-scoped variable 'Readable'.
readble.ts(1,5): error TS2451: Cannot redeclare block-scoped variable 'Readable'.
tsファイルを見ても間違いが見つからず苦労したが、同じディレクトリにあるファイルがnamespace を切らずに、同じ定義をしたからだった。
ちなみに、何回typescript の環境構築しても、わすれてしまうので、メモしておく。
npm init
npm install -D typescript // -D = --save-dev
tsc --init // typeconfig.json 作成
npm install @types/node --save-dev
今は、typings を使うことはいらない感じね。
まだまだ、Stream がまだまだので、少しづつ試してみる。