node.js流的错误处理

node.js流的错误处理,node.js,stream,Node.js,Stream,处理流错误的正确方法是什么?我已经知道有一个“错误”事件你可以听,但我想知道更多关于任意复杂情况的细节 首先,当您想要创建一个简单的管道链时,您会做什么: input.pipe(transformA).pipe(transformB).pipe(transformC). 如何正确地创建这些转换之一,以便正确处理错误 更多相关问题: 发生错误时,“结束”事件会发生什么情况?它永远不会被解雇吗?有时会被解雇吗?它是否依赖于转换/流?这里的标准是什么 是否存在通过管道传播错误的机制 域名能有效地解决

处理流错误的正确方法是什么?我已经知道有一个“错误”事件你可以听,但我想知道更多关于任意复杂情况的细节

首先,当您想要创建一个简单的管道链时,您会做什么:

input.pipe(transformA).pipe(transformB).pipe(transformC).

如何正确地创建这些转换之一,以便正确处理错误

更多相关问题:

  • 发生错误时,“结束”事件会发生什么情况?它永远不会被解雇吗?有时会被解雇吗?它是否依赖于转换/流?这里的标准是什么
  • 是否存在通过管道传播错误的机制
  • 域名能有效地解决这个问题吗?举个例子就好了
  • “错误”事件产生的错误是否具有堆栈跟踪?有时?从未?有办法从他们那里得到一个吗

    • 变换

      转换流既可读又可写,因此是真正好的“中间”流。因此,它们有时通过流被称为
      。它们在这方面类似于双工流,只是它们提供了一个很好的接口来操作数据,而不仅仅是通过发送数据。转换流的目的是在数据通过流进行管道传输时对其进行操作。例如,您可能需要执行一些异步调用,或者派生几个字段,重新映射某些内容,等等



      有关如何创建转换流,请参见和。你所要做的就是:

    • 包括流模块
    • 实例化(或继承)转换类
    • 实现一个
      \u transform
      方法,该方法采用
      (块、编码、回调)
      区块是您的数据。如果您使用的是
      objectMode=true
      ,则大多数情况下无需担心编码问题。处理完区块后,将调用回调。然后将该块推送到下一个流

      我建议,若你们想要一个很好的助手模块,它能让你们很容易地通过流完成任务

      对于错误处理,请继续阅读

      管道

      在管道链中,处理错误确实是非常重要的。根据,生成.pipe()不是为了转发错误。所以有点像

      var a = createStream();
      a.pipe(b).pipe(c).on('error', function(e){handleError(e)});
      
      。。。将只侦听流
      c
      上的错误。如果在
      a
      上发出错误事件,则不会向下传递,事实上会引发错误。要正确执行此操作,请执行以下操作:

      var a = createStream();
      a.on('error', function(e){handleError(e)})
      .pipe(b)
      .on('error', function(e){handleError(e)})
      .pipe(c)
      .on('error', function(e){handleError(e)});
      
      现在,尽管第二种方法更详细,但至少可以保留错误发生的上下文。这通常是件好事

      不过,如果您只想在目标位置捕获错误,而不太关心错误发生的位置,那么我发现有一个库非常有用

      结束

      触发错误事件时,不会(显式)触发结束事件。发出错误事件将结束流

      根据我的经验,域在大多数情况下都工作得很好。如果有未处理的错误事件(即在没有侦听器的流上发出错误),服务器可能会崩溃。现在,正如上面的文章所指出的,您可以将流包装在一个域中,该域应该能够正确地捕获所有错误

      var d = domain.create();
       d.on('error', handleAllErrors);
       d.run(function() {
           fs.createReadStream(tarball)
             .pipe(gzip.Gunzip())
             .pipe(tar.Extract({ path: targetPath }))
             .on('close', cb);
       });
      
      • 上面的代码示例来自
      域的美妙之处在于它们将保留堆栈痕迹。尽管事件流在这方面也做得很好


      要进一步阅读,请查看。非常深入,但非常有用,并提供了许多有用模块的链接。

      transform

      转换流既可读又可写,因此是真正好的“中间”流。因此,它们有时通过
    • 流被称为
      。它们在这方面类似于双工流,只是它们提供了一个很好的接口来操作数据,而不仅仅是通过发送数据。转换流的目的是在数据通过流进行管道传输时对其进行操作。例如,您可能需要执行一些异步调用,或者派生几个字段,重新映射某些内容,等等



      有关如何创建转换流,请参见和。你所要做的就是:

    • 包括流模块
    • 实例化(或继承)转换类
    • 实现一个
      \u transform
      方法,该方法采用
      (块、编码、回调)
      区块是您的数据。如果您使用的是
      objectMode=true
      ,则大多数情况下无需担心编码问题。处理完区块后,将调用回调。然后将该块推送到下一个流

      我建议,若你们想要一个很好的助手模块,它能让你们很容易地通过流完成任务

      对于错误处理,请继续阅读

      管道

      在管道链中,处理错误确实是非常重要的。根据,生成.pipe()不是为了转发错误。所以有点像

      var a = createStream();
      a.pipe(b).pipe(c).on('error', function(e){handleError(e)});
      
      。。。将只侦听流
      c
      上的错误。如果在
      a
      上发出错误事件,则不会向下传递,事实上会引发错误。要正确执行此操作,请执行以下操作:

      var a = createStream();
      a.on('error', function(e){handleError(e)})
      .pipe(b)
      .on('error', function(e){handleError(e)})
      .pipe(c)
      .on('error', function(e){handleError(e)});
      
      现在,尽管第二种方法更详细,但至少可以保留错误发生的上下文。这通常是件好事

      不过,如果您只想在目标位置捕获错误,而不太关心错误发生的位置,那么我发现有一个库非常有用

      结束

      触发错误事件时,不会(显式)触发结束事件。发出错误事件将结束流

      根据我的经验,域在大多数情况下都工作得很好。如果你
      safePipe(readable, [ transform1, transform2, ... ]);
      
      // CustomTransform.js
      CustomTransformStream.prototype._transform = function (data, enc, done) {
        var stream = this
        try {
          // Do your transform code
        } catch (e) {
          // Now based on the error type, with an if or switch statement
          stream.emit("CTError1", e)
          stream.emit("CTError2", e)
        }
        done()
      }
      
      // StreamImplementation.js
      someReadStream
        .pipe(CustomTransformStream)
        .on("CTError1", function (e) { console.log(e) })
        .on("CTError2", function (e) { /*Lets do something else*/ })
        .pipe(someWriteStream)
      
      var transformStream1 = new stream.Transform(/*{objectMode: true}*/);
      
      transformStream1.prototype._transform = function (chunk, encoding, done) {
        //var stream = this;
      
        try {
          // Do your transform code
          /* ... */
        } catch (error) {
          // nodejs style for propagating an error
          return done(error);
        }
      
        // Here, everything went well
        done();
      }
      
      // Let's use the transform stream, assuming `someReadStream`
      // and `someWriteStream` have been defined before
      someReadStream
        .pipe(transformStream1)
        .on('error', function (error) {
          console.error('Error in transformStream1:');
          console.error(error);
          process.exit(-1);
         })
        .pipe(someWriteStream)
        .on('close', function () {
          console.log('OK.');
          process.exit();
        })
        .on('error', function (error) {
          console.error(error);
          process.exit(-1);
         });
      
      const { pipeline, finished } = require('stream');
      
      pipeline(
        input, 
        transformA, 
        transformB, 
        transformC, 
        (err) => {
          if (err) {
            console.error('Pipeline failed', err);
          } else {
            console.log('Pipeline succeeded');
          }
      });
      
      
      finished(input, (err) => {
        if (err) {
          console.error('Stream failed', err);
        } else {
          console.log('Stream is done reading');
        }
      });
      
      const pipe = require('multipipe')
      
      // pipe streams
      const stream = pipe(streamA, streamB, streamC) 
      
      
      // centralized error handling
      stream.on('error', fn)