为什么这个程序不输出任何数据?

时间:2013-07-18 21:48:09

标签: node.js

我正在搞乱Node.js 0.10 Stream类,试图弄清楚如何使用它们。我不确定为什么这个实验不起作用。它应该输出字母表的字母到HTTP响应对象,但不是。我用一些评论注释了源代码。

谢谢!

var Readable = require('stream').Readable
  , inherits = require('util').inherits
  , http = require('http');

/**
 * A stream that streams the English alphabet
 */

function AlphabetStream() {
  Readable.call(this);
  this.code = this.offset = 'a'.charCodeAt(0);
  this.last = 'z'.charCodeAt(0);
}

inherits(AlphabetStream, Readable);

AlphabetStream.prototype._read = function(size) {
  for (var i = 0; i < size; i++)
    this.push(this.next_char());
  this.push(null);
};

AlphabetStream.prototype.next_char = function() {
  var cycle = this.last+1;
  return String.fromCharCode((++this.code % cycle) + this.offset);
};


/**
 * An HTTP server, prints the first n letters of the English alphabet
 */

var server = http.createServer(function(req, res) {
  // $ curl localhost:3001/?size=11

  var size = require('url').parse(req.url, true).query.size;

  if (size) {
    var rs = new AlphabetStream;
    rs.pipe(res); // This calls `_read()` with `size` 16kb
    rs.read(parseInt(size)); // This also calls `_read()` with `size` 16kb
  }

  res.end(''); // Nothing gets printed, despite the pipe and the reading.
});

server.listen(3001, function() {
  console.log('Listening on 3001');
});

1 个答案:

答案 0 :(得分:3)

看一下这段代码:

if (size) {
  var rs = new AlphabetStream;
  rs.pipe(res); // This calls `_read()` with `size` 16kb
  rs.read(parseInt(size)); // This also calls `_read()` with `size` 16kb
}

res.end(''); // Nothing gets printed, despite the pipe and the reading.

您可以在实际管道发生之前结束响应(最后一行)(这是因为.pipe是异步的)。你应该做的是这样的事情:

if (size) {
  var rs = new AlphabetStream;
  rs.pipe(res);
  rs.read(parseInt(size));
} else {
  // NOTE THE ELSE STATEMENT
  res.end('');
}

.pipe函数将负责结束目标流(即响应),除非另有明确说明,请参阅文档:

http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options

编辑至于为什么16kb?好吧,我不得不做一些测试,似乎这是.pipe的默认行为(我不确定如何改变它说实话)。首先要注意这一行:

  rs.read(parseInt(size));

完全无用(你可以删除它)。 .pipe将负责阅读数据。现在,默认行为是读取16kb数据的块。所以为了做你想做的事,你应该把size传递给AlphabetStream的构造函数,就像这样:

function AlphabetStream(size) {
  Readable.call(this);
  this.code = this.offset = 'a'.charCodeAt(0);
  this.last = 'z'.charCodeAt(0);
  this.size = size; // <--- store size here
}

inherits(AlphabetStream, Readable);

AlphabetStream.prototype._read = function(size) {
  // this allows the stream to be a true stream
  // it reads only as much data as it can
  // but .read can be called multiple times without issues
  // with a predefined limit

  var chunk = Math.min(size, this.size);
  this.size -= chunk;
  for (var i = 0; i < chunk; i++) {
    this.push(this.next_char());
  }
  if (!this.size) {
    // end the stream only when the limit is reached
    this.push(null);
  }
};

毕竟流不应该取决于您读取的数据量。然后你做:

if (size) {
  var rs = new AlphabetStream(parseInt(size));
  rs.pipe(res);
} else {
  res.end('');
}