如何对Node.js流管道中的错误事件做出正确反应?

fre*_*nya 2 javascript stream node.js

我一直在努力理解错误处理如何在Node.js流管道中工作,最终我使用了一个简单的游乐场进行试验,这对我来说很清楚。

我将其发布为一个自我解答的问题。也许有人觉得这很有帮助:)

fre*_*nya 6

操场

让我们创建连接到管道中的三个名为PassThrough的流,并观察各个事件。

var stream = require('stream');

function observedStream(name) {
  var s = new stream.PassThrough({objectMode: true});

  s.on('error', function(err) { console.log(name + ': ' + err); });
  s.on('data', function(data) { console.log(name + ': ' + data); });
  s.on('finish', function() { console.log(name + ': FINISH'); });
  s.on('end', function() { console.log(name + ': END'); });
  s.on('close', function() { console.log(name + ': CLOSE'); });
  s.on('unpipe', function() { console.log(name + ': UNPIPE'); });

  return s;
}

var s1 = observedStream('S1'),
    s2 = observedStream('S2'),
    s3 = observedStream('S3');

s1.pipe(s2).pipe(s3);
Run Code Online (Sandbox Code Playgroud)

标准行为

写入管道非常简单。我们只是data从每个阶段得到一个事件。

s1.write('Hello');
// S1: Hello
// S2: Hello
// S3: Hello
Run Code Online (Sandbox Code Playgroud)

让我们看看结束流时会发生什么?那里也没有惊喜。

s1.end();
// S1: FINISH
// S1: END
// S2: FINISH
// S2: UNPIPE
// S2: END
// S3: FINISH
// S3: UNPIPE
// S3: END
Run Code Online (Sandbox Code Playgroud)

错误处理

让我们尝试发出一个错误(显然,如果您调用了s1.end()上述方法,则需要首先重新创建管道)。

s1.emit('error', new Error('bazinga'));
// S1: Error: bazinga
Run Code Online (Sandbox Code Playgroud)

注意这里什么也没有发生。您可以继续写S1,就像什么都没发生一样。管道未关闭。

当出现“中游”错误时,事情会变得更加有趣:)

s2.emit('error', new Error('bazinga'));
// S2: UNPIPE
// S2: ERROR
Run Code Online (Sandbox Code Playgroud)

请注意,Node.js会自动从S2取消对S1流的管道传输,除此之外没有其他操作。也就是说,S1流仍在等待某人读取其数据,而S2流仍通过管道传递到S3中,并且可以(理论上)发送数据。

这是您需要在代码中处理的事情!一种选择是调用end()S1和S2上的方法。另一个方法是使用该pipe()方法重新连接S1和S2 。两者似乎都可以工作,但这都取决于您的特定使用情况。

学分

  1. Ben Nadel博客的这篇文章为我指明了正确的方向。
  2. 这个SO问题从稍微不同的角度解决了一个相似的主题。答案中也有一些很好的指示。