如何在没有Duplexer软件包的情况下解决NodeSchool的双工器挑战

时间:2014-04-30 12:21:48

标签: javascript node.js stream duplex

问题(可从nodeschool.io/#stream-adventure下载)

  

编写一个程序,用于导出从中生成进程的函数   cmd字符串和args数组,并返回单个双工流   将生成过程的stdin和stdout连接在一起。有   你可以在这里使用一个非常方便的模块:双工器。双工器模块   导出加入的单个函数duplexer(writable, readable)   将可写流和可读流合并为一个,   可读/可写双工流。

官方解决方案

var spawn = require('child_process').spawn;
var duplexer = require('duplexer');

module.exports = function (cmd, args) {
    var ps = spawn(cmd, args);
    return duplexer(ps.stdin, ps.stdout);
}; 

此代码基本上执行以下操作:

var spawn = require("child_process").spawn,
    Stream = require("stream");

module.exports = function (cmd, args) {
    var ps = spawn(cmd, args),
        stream = new Stream();
    stream.write = function (chunk, enc, cb) { ps.stdin.write(chunk, enc, cb); }
    stream.end = function (chunk, enc, cb) { ps.stdin.end(chunk, enc, cb); }
    ps.stdout.on("data", function (chunk) { stream.emit("data", chunk); });
    ps.stdout.on("end", function () { stream.emit("end"); });
    return stream;
}; 

没有双工器包的解决方案

我尝试通过继承Duplex类来解决问题:

var spawn = require("child_process").spawn,
    Stream = require("stream");

require("util").inherits(Dx, Stream.Duplex);
function Dx(stdin, stdout) {
    Stream.Duplex.call(this);
    this.stdin = stdin;
    this.stdout = stdout;
}
Dx.prototype._write = function (chunk, enc, cb) { this.stdin.write(chunk, enc, cb); };
Dx.prototype._read = function (size) { return this.stdout.read(size); };

module.exports = function (cmd, args) {
    var ps = spawn(cmd, args),
        stream = new Dx(ps.stdin, ps.stdout);
    return stream;
};

当我测试这个(stream-adventure verify program.js)时,测试程序打印ACTUAL vs. EXPECTED表(它看起来是正确的),但之后它会被卡住。我的代码出了什么问题?谢谢你的帮助。

更新

添加此行可解决问题:

Dx.prototype.end = function (chunk, enc, cb) { this.stdin.end(chunk, enc, cb); }

所以问题是,为什么实施_read_write方法还不够?

1 个答案:

答案 0 :(得分:0)

在所有其他操作完成后,

process.stdin仍然存在,这就是该过程未结束的原因。为了让流程结束,通常使用方法process.stdin.pause(),因为您可以在此之后恢复它。

您可以尝试覆盖.end()方法,但这不是一个好习惯,更好的做法是:

#1 如果您知道要为此流编写的结束消息,则应在.resume()实施中添加._write()方法:

dstream._write = function (chunk, encoding, callback) {

    this.stdin.write(chunk, encoding, callback);

    if (someConditionToEnd) {
        this.stdin.pause();
    }
};

#2 收听结束活动:

/*
inside the stream prototype constructor
*/

this.on('end', function () {
    this.stdin.pause();
});