处理流错误的正确方法是什么?我已经知道您可以收听一个“错误”事件,但我想了解有关任意复杂情况的更多详细信息。
对于初学者,当你想做一个简单的管道链时你会怎么做:
input.pipe(transformA).pipe(transformB).pipe(transformC)...
以及如何正确创建其中一种转换以便正确处理错误?
更多相关问题:
转换
转换流既可读又可写,因此是非常好的“中间”流。出于这个原因,它们有时被称为through流。它们在这种方式上类似于双工流,只是它们提供了一个很好的接口来操作数据,而不仅仅是发送数据。转换流的目的是在数据通过流传输时对其进行操作。例如,您可能想要进行一些异步调用,或者派生几个字段,重新映射一些东西等。
through
有关如何创建转换流的信息,请参见此处和此处。您所要做的就是:
_transform
(chunk, encoding, callback)
块是您的数据。大多数情况下,如果您在objectMode = true. 当您完成处理块时调用回调。然后将该块推送到下一个流。
objectMode = true
如果你想要一个很好的帮助模块,它可以让你非常轻松地通过流,我建议through2。
对于错误处理,请继续阅读。
管道
在管道链中,处理错误确实很重要。根据这个线程.pipe() 不是为了转发错误而构建的。所以像…
var a = createStream(); a.pipe(b).pipe(c).on('error', function(e){handleError(e)});
… 只会监听流上的错误c。如果在 上发出错误事件a,则不会传递下去,实际上会抛出。要正确执行此操作:
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)});
现在,虽然第二种方法更冗长,但您至少可以保留错误发生位置的上下文。这通常是一件好事。
如果您只想在目的地捕获错误并且您不太关心它发生的位置,那么我发现一个库很有帮助event- stream。
结尾
当一个错误事件被触发时,结束事件将不会被触发(显式地)。发出错误事件将结束流。
域
根据我的经验,域名在大多数情况下都运行良好。如果您有未处理的错误事件(即在没有侦听器的情况下在流上发出错误),服务器可能会崩溃。现在,正如上面的文章所指出的,您可以将流包装在应该正确捕获所有错误的域中。
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); });
域的美妙之处在于它们将保留堆栈跟踪。尽管事件流在这方面也做得很好。
如需进一步阅读,请查看流手册。相当深入,但超级有用,并提供了许多有用模块的链接。