ストリームでエラーを処理する正しい方法は何ですか? リッスンできる「エラー」イベントがあることはすでに知っていますが、任意の複雑な状況についてさらに詳しく知りたいです。
まず、単純なパイプ チェーンを実行したい場合はどうすればよいでしょうか。
input.pipe(transformA).pipe(transformB).pipe(transformC)...
そして、エラーが正しく処理されるように、これらの変換を適切に作成するにはどうすればよいでしょうか?
関連するその他の質問:
- エラーが発生すると、「end」イベントはどうなりますか? 決して発生しないのですか? 時々発生するのですか? 変換/ストリームに依存しますか? ここでの標準は何ですか?
- パイプを通じてエラーを伝播させるメカニズムはありますか?
- ドメインはこの問題を効果的に解決しますか? 例があると助かります。
- 「エラー」イベントから発生するエラーにはスタック トレースがありますか? 時々ありますか? まったくありませんか? そこからスタック トレースを取得する方法はありますか?
ベストアンサー1
変身
変換ストリームは読み取りと書き込みの両方が可能で、非常に優れた「中間」ストリームです。このため、through
ストリームと呼ばれることもあります。この点ではデュプレックス ストリームに似ていますが、データを単に送信するのではなく、データを操作するための優れたインターフェイスを提供します。変換ストリームの目的は、ストリームを介してパイプされるデータを操作することです。たとえば、非同期呼び出しを実行したり、いくつかのフィールドを派生させたり、いくつかのものを再マップしたりする必要がある場合があります。
変換ストリームの作成方法については、ここそしてここあなたがしなければならないことは、次のとおりです。
- ストリームモジュールを含める
- Transformクラスをインスタンス化(または継承)する
_transform
を受け取るメソッドを実装します(chunk, encoding, callback)
。
チャンクはデータです。 で作業している場合、ほとんどの場合、エンコードについて心配する必要はありませんobjectMode = true
。チャンクの処理が完了すると、コールバックが呼び出されます。その後、このチャンクは次のストリームにプッシュされます。
ストリームを非常に簡単に実行できる便利なヘルパーモジュールが必要な場合は、2 を通して。
エラー処理については、読み続けてください。
パイプ
パイプチェーンでは、エラーの処理は確かに簡単ではありません。このスレッド.pipe() はエラーを転送するようには構築されていません。つまり、次のようなものになります...
var a = createStream();
a.pipe(b).pipe(c).on('error', function(e){handleError(e)});
... は、ストリーム 上のエラーのみをリッスンしますc
。 でエラー イベントが発行された場合a
、それは渡されず、実際にはスローされます。これを正しく行うには、次の操作を行います。
var a = createStream();
a.on('error', function(e){handleError(e)})
.pipe(b)
.on('error', function(e){handleError(e)})
.pipe(c)
.on('error', function(e){handleError(e)});
さて、2 番目の方法はより冗長ではありますが、少なくともエラーが発生した場所のコンテキストを保持できます。これは通常、良いことです。
しかし、宛先でのエラーのみをキャプチャしたい場合や、どこで発生したかはあまり気にしない場合に役立つライブラリが1つあります。イベントストリーム。
終わり
エラー イベントが発生すると、終了イベントは (明示的に) 発生しません。エラー イベントが発生すると、ストリームが終了します。
ドメイン
私の経験では、ドメインはほとんどの場合、非常にうまく機能します。処理されないエラー イベント (つまり、リスナーのないストリームでエラーが発生する) がある場合、サーバーがクラッシュする可能性があります。上記の記事で指摘されているように、ストリームをドメインでラップすると、すべてのエラーを適切にキャッチできます。
var d = domain.create();
d.on('error', handleAllErrors);
d.run(function() {
fs.createReadStream(tarball)
.pipe(gzip.Gunzip())
.pipe(tar.Extract({ path: targetPath }))
.on('close', cb);
});
- 上記のコードサンプルはこの郵便受け
ドメインの優れた点は、スタック トレースが保持されることです。ただし、event-stream もこの点については優れています。
さらに詳しくは、ストリームハンドブック1 . かなり詳細ですが、非常に役立ち、多くの役立つモジュールへの素晴らしいリンクが提供されています。
1:注: 元の GitHub リポジトリは 2022 年 8 月頃に削除されたため、このリンクは archive.org を指しています。