从 JavaScript 对象创建 Node.js 可读流——最简单的方法

Posted

技术标签:

【中文标题】从 JavaScript 对象创建 Node.js 可读流——最简单的方法【英文标题】:Creating a Node.js Readable stream from a JavaScript object — The simplest possible way 【发布时间】:2014-02-03 04:06:23 【问题描述】:

谁能解释为什么我在使用节点 v0.10.21 运行以下代码后出现错误?

我知道我可以 JSON.stringify() 该对象以获得或多或少相同的结果,这里的重点是在 objectMode 设置为 true 时理解 stream.Readable。

错误:

net.js:612
    throw new TypeError('invalid data');
          ^
TypeError: invalid data
    at WriteStream.Socket.write (net.js:612:11)
    at write (_stream_readable.js:583:24)
    at flow (_stream_readable.js:592:7)
    at _stream_readable.js:560:7
    at process._tickCallback (node.js:415:13)
    at Function.Module.runMain (module.js:499:11)
    at startup (node.js:119:16)
    at node.js:901:3

代码:

var stream = require('stream');
var edad = require(__dirname + '/public/edad.json');

var rs = new stream.Readable( objectMode: true );

rs.push(edad);
rs.push(null);
rs.pipe(process.stdout);

【问题讨论】:

致更多读者:在另一个关于类似上下文的问题中写了一个答案。链接:(***.com/a/35886734/1453339) 【参考方案1】:

rs 是 objectMode 流,但 process.stdout 不是,因此它期望将 Buffer 实例写入其中。因为它得到了错误的数据类型,所以它抛出了一个错误。

如果您希望能够像这样对对象进行管道传输,则需要有一个支持写入对象和读取缓冲区的中间流。

类似这样的:

var stream = require('stream');
var util = require('util');

function StringifyStream()
    stream.Transform.call(this);

    this._readableState.objectMode = false;
    this._writableState.objectMode = true;

util.inherits(StringifyStream, stream.Transform);

StringifyStream.prototype._transform = function(obj, encoding, cb)
    this.push(JSON.stringify(obj));
    cb();
;


var edad = require(__dirname + '/public/edad.json');

var rs = new stream.Readable( objectMode: true );
rs.push(edad);
rs.push(null);

rs.pipe(new StringifyStream()).pipe(process.stdout);

【讨论】:

反正我还在串化那个对象,对吧?有没有办法将对象转储到目的地,让这个人把它变成一个字符串? @n370 不确定我是否关注。如果您只返回rs,这就是您所得到的。您只是不能将rs 直接通过管道传输到需要字符串的流。你当然可以把它留给目标流来接受一个对象。 哦,我明白了!所以在我们的例子中,我们可以让process.stdout 期望一个对象在输出到stdout 之前将其更改为字符串吗?我们可以用纯 Node 和 JS 来实现吗?我非常感谢您的关注@loganfsmyth 很遗憾,没有,这就是为什么您需要像 StringifyStream 这样的中间体。您可能会编写您的流来支持两者,但现实情况是这实际上取决于您的用例。有人可能想像 XML 一样轻松地编码,所以让 stdout 对此一无所知是没有意义的。【参考方案2】:

正如 loganfsmyth 所说,rsobjectMode 中,而 process.stdout 不在。因此,它期望将Buffers/Strings 写入其中,并在收到Object 时抛出TypeError

我们需要将Objects的流转换成文本,这就是JSONStream要做的事情:

JSONStream = require('JSONStream');
rs.pipe(JSONStream.stringify()).pipe(process.stdout);

【讨论】:

【参考方案3】:

我是一个对 Node 了解不多的人(我只需要让我的 Gulp 设置正常工作)。因此,我需要 20 多行代码和像 stream.push(null) 这样的奇怪调用来处理流中的变量这一事实似乎有点疯狂。

这对我有用:

var data =  "prop1": "val1", "prop2": "val2" ;
var dest = 'path/to/dest/config.json';
var s = require('stream');

var stream = new s.Readable();
stream.push(JSON.stringify(data));    // stream apparently does not accept objects
stream.push(null);                    // no idea why this is needed, but it is

return stream
    .pipe()                           // whatever you need
    .pipe($.fs.createWriteStream(dest));

【讨论】:

我尝试编辑答案以改进它,但似乎队列已满。 stream.push(null) 实际上代表流的结尾(如\0)。另外,可读流显然是一个转换为流的字符串数组,所以所有元素都必须是字符串。

以上是关于从 JavaScript 对象创建 Node.js 可读流——最简单的方法的主要内容,如果未能解决你的问题,请参考以下文章

node.js从基础到实战六阶段系统

如何将 JavaScript 对象/数组发送到前端 - node.js 应用程序

Node.js——Buffer

如何从node js文件中调用一个vanilla JavaScript函数?

nodeJS从入门到进阶

如何通过使用 node.js 从实时 json 数据中提取特定字段来创建新的单个 json 对象