我刚开始学习节点中的流。我在内存中有一个字符串,我想把它放在一个应用转换的流中,并将其传递给process.stdout
。我试图这样做:
var through = require('through');
var stream = through(function write(data) {
this.push(data.toUpperCase());
});
stream.push('asdf');
stream.pipe(process.stdout);
stream.end();
它不起作用。当我在cli via节点上运行脚本时,没有任何内容发送到stdout并且不会抛出任何错误。我有几个问题:
push
和queue
之间的区别是什么?end()
之前或之后致电pipe()
是否重要?end()
是否等同于push(null)
?谢谢!
答案 0 :(得分:2)
只需使用vanilla stream API
即可var Transform = require("stream").Transform;
// create a new Transform stream
var stream = new Transform({
decodeStrings: false,
encoding: "ascii"
});
// implement the _transform method
stream._transform = function _transform(str, enc, done) {
this.push(str.toUpperCase() + "\n";
done();
};
// connect to stdout
stream.pipe(process.stdout);
// write some stuff to the stream
stream.write("hello!");
stream.write("world!");
// output
// HELLO!
// WORLD!
或者您可以构建自己的流构造函数。这实际上就是要使用流API的方式
var Transform = require("stream").Transform;
function MyStream() {
// call Transform constructor with `this` context
// {decodeStrings: false} keeps data as `string` type instead of `Buffer`
// {encoding: "ascii"} sets the encoding for our strings
Transform.call(this, {decodeStrings: false, encoding: "ascii"});
// our function to do "work"
function _transform(str, encoding, done) {
this.push(str.toUpperCase() + "\n");
done();
}
// export our function
this._transform = _transform;
}
// extend the Transform.prototype to your constructor
MyStream.prototype = Object.create(Transform.prototype, {
constructor: {
value: MyStream
}
});
现在像这样使用它
// instantiate
var a = new MyStream();
// pipe to a destination
a.pipe(process.stdout);
// write data
a.write("hello!");
a.write("world!");
输出
HELLO!
WORLD!
关于.push
与.write
的其他一些说明。
.write(str)
将数据添加到可写缓冲区。它应该被称为外部。如果您将流视为双工文件句柄,它就像fwrite
一样,只是缓冲。
.push(str)
将数据添加到可读缓冲区。它只能从我们的流中调用。
.push(str)
可以多次调用。观察如果我们将功能更改为
function _transform(str, encoding, done) {
this.push(str.toUpperCase());
this.push(str.toUpperCase());
this.push(str.toUpperCase() + "\n");
done();
}
输出
HELLO!HELLO!HELLO!
WORLD!WORLD!WORLD!
答案 1 :(得分:2)
首先,您要使用write()
,而不是push()
。 write()
将数据放入流中,push()
将数据推出流;您在实施自己的push()
,Readable
或Duplex
流时仅使用Transform
。
其次,您只需要{<1}}数据到后设置正如@naomik指出的那样,这通常不正确,因为write()
(或添加一些事件侦听器)。如果您写入一个没有连接到另一端的数据流,那么您编写的数据将会丢失。pipe()
流将会缓冲区Writable
。在您的示例中,您需要在write()
之后write()
。否则,该过程将在向pipe()
写入任何内容之前结束。这可能是由于STDOUT
模块的实现方式,但我肯定不知道。
因此,考虑到这一点,您可以对示例进行一些简单的更改以使其工作:
through
现在,提出您的问题:
var through = require('through');
var stream = through(function write(data) {
this.push(data.toUpperCase());
});
stream.pipe(process.stdout);
stream.write('asdf');
stream.end();
,就像我们在您的示例中使用write()
一样。stream.wrtie('asdf')
功能,您的意思是queue()
吗?就像我上面说的那样,write()
用于将数据放入流中,write()
用于将数据推出流。只在您自己的流实施中调用push()
。push()
。 end()
基本上说:“好的,我现在已经完成了。请完成你正在做的事情并关闭游戏。”end()
几乎相当于push(null)
。话虽这么说,除非你在你自己的流实现中做(如上所述),否则不要调用end()
。调用push(null)
几乎总是更合适。答案 2 :(得分:0)
基于流(http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options)
的示例并通过(https://www.npmjs.org/package/through)
看起来你没有正确使用你的流......如果你使用write(...)而不是push(...)会怎么样?