【问题标题】:Can an event based read function ever run out of order?基于事件的读取功能会出现故障吗?
【发布时间】:2016-11-25 08:24:06
【问题描述】:

假设我使用 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() 是否有可能出现故障并因此导致输出流被打乱?我应该考虑使用某种同步循环而不是这个异步事件处理程序吗?

【问题讨论】:

    标签: node.js asynchronous stdin


    【解决方案1】:

    JavaScript 执行本身是单线程的,所以只要你只是在事件处理程序内部执行同步操作,就没有问题。

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

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

    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();
    });
    

    【讨论】:

    • 感谢您对如何进行的解释和建议。坦率地说,虽然我对这变成了多少样板文件感到有点不安,只是为了一次迭代一条流。我想我有点太习惯在 Unix shell 中的生活了,其中行操作是常态。我想知道我是否会更好地通过迭代来做其他事情,并且一次只调用这个特定的脚本一行。这将是很多调用,但考虑到我实际上在其中进行解析的库的开销并不会那么重要。
    • 你能澄清一点吗?您说曾经运行过rl.pause()“也不是万无一失的”,但是如果我严格遵守该事件处理程序中的同步函数调用怎么办?如果我没有在其中执行任何 aSync 操作,我是否足够安全地使用我拥有的代码?
    • 如果你只是做同步操作,你不必担心改变任何东西,因为 js 是单线程的,这意味着在你的事件处理函数正在执行的同时不能执行其他 js。这意味着无需暂停/恢复 readline 实例或输入流。但是如果你曾经做过异步操作,你可能需要像我给出的代码示例那样的东西。
    猜你喜欢
    • 2012-12-08
    • 2018-11-12
    • 2011-01-07
    • 2023-04-09
    • 1970-01-01
    • 1970-01-01
    • 2012-10-31
    • 1970-01-01
    • 2011-06-26
    相关资源
    最近更新 更多