Node の Stream 周りでちょっと面白い問題に行き当たったので、メモしておきます。
簡略化すると・・・
someStream.once('error', function (err) {
console.log('You\'ve got an error:', err);
});
someStream.pipe(otherStream);
としていて、someStream.emit('error', err); すると、stream error が throw されるという問題です。
pipe は他にエラーハンドラーが登録されていないと stream error を throw するのですが、once, pipe の順番が直接の原因でした。
原理は以下のような感じです。
-
onceがエラーハンドラーを登録する。 -
pipeが内部でエラーハンドラーを登録する。 -
errorイベントがemitされる。 -
- のエラーハンドラーがまず実行される。
-
onceなので、1. のエラーハンドラーが削除される。 -
- で登録されたエラーハンドラーが他のエラーハンドラーの有無をチェックするが、見つからないので stream error を throw する。
解決するには、以下のどちらかです。
-
onceのかわりにonを使う。 -
pipe,onceの順番にする。2. 1. 3. 6. 4. 5. の順番で実行され、6. ではまだ 1. のエラーハンドラーが登録されているため stream error が起きません。
Stream2 の Readable や Transform を使っていれば error が複数回 emit されることはないようですが、Stream の実装によっては複数回 emit されるので、on を使っておくのが無難なんですかね。