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
を使っておくのが無難なんですかね。