如何强制Node.js转换流完成?

时间:2015-05-14 04:29:31

标签: node.js

请考虑以下情形。我有两个节点转换流:

转换流1

function T1(options) {
  if (! (this instanceof T1)) {
    return new T1(options);
  }

  Transform.call(this, options);
}
util.inherits(T1, Transform);

T1.prototype._transform = function(chunk, encoding, done) {
  console.log("### Transforming in t1");
  this.push(chunk);
  done();
};

T1.prototype._flush = function(done) {
  console.log("### Done in t1");
  done();
};

转换流2

function T2(options) {
  if (! (this instanceof T2)) {
    return new T2(options);
  }

  Transform.call(this, options);
}
util.inherits(T2, Transform);

T2.prototype._transform = function(chunk, encoding, done) {
  console.log("### Transforming in t2");
  this.push(chunk);
  done();
};

T2.prototype._flush = function(done) {
  console.log("### Done in t2");
  done();
};

并且,我想在返回响应之前应用这些转换流。我有一个简单的HTTP服务器,在每个请求中,我获取资源并希望将这些转换应用于此获取的资源,然后将第二个转换的结果发送到原始响应:

var options = require('url').parse('http://localhost:1234/data.json');
options.method = 'GET';

http.createServer(function(req, res) {
  var req = http.request(options, function(httpRes) {
    var t1 = new T1({});
    var t2 = new T2({});

    httpRes
      .pipe(t1)
      .pipe(t2)
      .on('finish', function() {
        // Do other stuff in here before sending request back
        t2.pipe(res, { end : true });
      });
  });

  req.end();
}).listen(3001);

最终,finish事件永远不会被调用,并且请求会挂起并超时,因为响应永远不会被解决。我注意到如果我只是将t2传递给res,它似乎工作正常:

  .pipe(t1)
  .pipe(t2)
  .pipe(res, { end : true });

但是,这种情况似乎不可行,因为我需要在返回响应之前做一些额外的工作。

1 个答案:

答案 0 :(得分:1)

发生这种情况是因为您需要让节点知道流正在某处消耗,否则最后一个流只会填满缓冲区,并且考虑到您的数据比highwaterMark选项(通常为16)更长,然后停止等待要消耗的数据。

有三种方法可以完整地使用流:

  • 管道到可读流(您在问题的第二部分中所做的)
  • 通过调用流的read方法
  • 来读取连续的块
  • 聆听"data"事件(主要是stream.on("data", someFunc))。

最后一个选项是最快的,但会导致使用流而不查看内存使用情况。

我还注意到使用"finish"事件可能有点误导,因为它在读取最后一个数据时被调用,但不一定被发出。在转换流上,因为它是可读的,所以使用"end"事件要好得多。