转变
转换流既可读又可写,因此确实是很好的“中间”流。因此,有时将它们称为through
流。它们在这种方式上类似于双工流,不同之处在于它们提供了一个不错的接口来操纵数据,而不仅仅是发送数据。转换流的目的是操纵通过流传输通过流的数据。例如,您可能要进行一些异步调用,或者派生几个字段,重新映射一些内容,等等。
有关如何创建转换流的信息,请参见此处和此处。您所要做的就是:
- 包括流模块
- 实例化(或继承自)Transform类
- 实现一个
_transform
需要一个的方法(chunk, encoding, callback)
。
块就是您的数据。在大多数情况下,如果您使用,就无需担心编码objectMode = true
。处理完块后,将调用回调。然后将这一块推送到下一个流。
如果您想要一个很好的帮助程序模块,它将使您真正非常轻松地完成流操作,我建议through2。
对于错误处理,请继续阅读。
管
在管道链中,处理错误确实是不平凡的。根据该线程,不会构建.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)});
现在,尽管第二种方法较为冗长,但您至少可以保留错误发生位置的上下文。这通常是一件好事。
我发现一个库对您有帮助,但是如果您只想捕获目标位置的错误,而又不太关心事件发生的地方,那就是事件流。
结束
当引发错误事件时,将不会(明确地)引发结束事件。错误事件的发出将结束流。
域
以我的经验,域名在大多数情况下都非常有效。如果您有未处理的错误事件(即在没有侦听器的情况下在流上发出错误),则服务器可能会崩溃。现在,正如上面的文章所指出的,您可以将流包装在应该正确捕获所有错误的域中。
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);
});
域的优点在于,它们将保留堆栈跟踪。尽管事件流在这方面也做得很好。
要进一步阅读,请查阅流手册。很深入,但是非常有用,并且提供了许多有用模块的出色链接。
Promise
框架使其变得更加简单