基于事件的读取功能是否会出现故障?

时间:2016-11-25 08:24:06

标签: node.js asynchronous stdin

鉴于我使用nodejs readline库迭代STDIN流中的每一行的情况,对它进行一些处理并将其写回STDOUT,如下例所示:

var rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
  terminal: false
});
function my_function(line) {
    var output = ...(line);
    process.stdout.write(output);
}
rl.on('line', my_function);

我担心我正在进行的处理将花费非常不同的时间,具体取决于行内容,因此某些行将很快返回,而其他行需要一些时间来整理。 my_function()是否可能无序运行,从而导致输出流被扰乱?我应该考虑使用某种同步循环而不是这种异步事件处理程序吗?

1 个答案:

答案 0 :(得分:2)

JavaScript执行本身是单线程的,因此只要您只在事件处理程序中执行同步操作,就没有问题。

如果 在事件处理程序中执行异步操作,则可能在异步操作之前发出另一个'line'事件完成了。在这种情况下,一旦完成异步操作,首先需要rl.pause()然后rl.resume()。但是,这并非万无一失,因为如果从输入流中读取的当前数据块有多个换行符,'line'事件仍可在rl.pause()之后发出。

因此,如果您在事件处理程序中执行异步操作,那么您最好只是自己从流中读取,以便您可以更好地控制解析行为。这实际上很容易做到,例如:

function parseStream(stream, callback) {
  // Assuming all stream data is text and not binary ...
  var buffer = '';

  var RE_EOL = /\r?\n/g;

  stream.on('data', function(data) {
    buffer += data;
    processBuffer();
  });

  stream.on('end', callback);

  stream.on('error', callback);

  function processBuffer() {
    var idx = RE_EOL.exec(buffer);
    if (~idx) {
      // Found a line ending

      var line = buffer.slice(0, RE_EOL.index);
      buffer = buffer.slice(RE_EOL.index + RE_EOL[0].length);

      stream.pause();
      callback(null, line, processBuffer);
    } else {
      stream.resume();
    }
  }
}

// ...

processStream(process.stdin, function(err, line, done) {
  if (err) throw err;

  if (line === undefined) {
    // No more data will be available (stream ended)
    console.log('(Stream ended!)');
    return;
  }

  // Do something with `line`
  console.log(line);

  // Call `done()` whenever your async operation(s) are all finished
  done();
});