简体   繁体   English

为什么Express的默认错误处理程序从Readable流中发出错误时会捕获错误?

[英]Why does the Express' default error handler catch error when emitting from Readable stream?

I installed a boilerplate Express app using the command line express stream_test . 我使用命令行express stream_test安装了样板Express应用程序。 I replaced the default /routes/index.js with: 我将默认的/routes/index.js替换为:

var express = require('express');
var router = express.Router();
var ReadFile = require('./readFile.js');

/* GET home page. */
router.get('/', function(req, res, next) {
  var readFile = ReadFile();
  readFile
  .on('data', function(data) {
    res.write(data);
  })
  .on('end', function() {
    res.end();
  })
  .on('error', function(err) {
    console.log(err);
  });
});

module.exports = router;

readFile.js is just a simple wrapper for fs.createReadStream : readFile.js只是fs.createReadStream的简单包装:

var Readable = require('stream').Readable;
var util = require('util');
var fs = require('fs');

function ReadFile(options) {
  if (!(this instanceof ReadFile)) {
    return new ReadFile(options);
  }
  Readable.call(this);

  options = options || {};

  var self = this;

  fs.createReadStream('pride_and_prejudice.txt')
  .on('data', function(data) {
    self.push(data);
  })
  .on('end', function(end) {
    self.push(null);
  });

}

util.inherits(ReadFile, Readable);
ReadFile.prototype._read = function _readGetDeals() {};

module.exports = ReadFile;

That works totally fine. 那完全正常。 It outputs the contents of pride_and_prejudice.txt to the screen when calling the route. 调用路由时, pride_and_prejudice.txt的内容输出到屏幕。

But let's say some requirements are not met and I want to throw an error before streaming the data: 但是,我们可以说某些要求没有得到满足,我想在流传输数据之前抛出一个错误:

var Readable = require('stream').Readable;
var util = require('util');
var fs = require('fs');

function ReadFile(options) {
  if (!(this instanceof ReadFile)) {
    return new ReadFile(options);
  }
  Readable.call(this);

  options = options || {};

  var self = this;

  if (!options.okay) {
    return self.emit('error', new Error('Forced crash'));
  }

  fs.createReadStream('pride_and_prejudice.txt')
  .on('data', function(data) {
    self.push(data);
  })
  .on('end', function(end) {
    self.push(null);
  });

}

That throws an error Forced crash. 这将引发错误Forced crash. when options.okay is false . options.okayfalse I expect to catch the error in my index.js route while listening on the error . 我希望在侦听错误时在index.js路由中捕获该error But the handler never executes. 但是处理程序永远不会执行。 To my very surprise the default error handler in app.js is catching the error: 令我惊讶的是, app.js的默认错误处理程序正在捕获错误:

if (app.get('env') === 'development') {
  app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
      message: err.message,
      error: err
    });
  });
}

This is driving me nuts. 这让我发疯。 How does the error end up there? 错误如何结束? Why isn't the event listener catching it? 为什么事件监听器没有捕获到它?

1) When you emit error the ReadFile returns nothing, as well as the nearest trap for errors outside of the router module, then after the call ReadFile she called. 1)当您发出error ,ReadFile不返回任何内容,以及路由器模块外部最近的错误陷阱,然后在调用ReadFile之后进行调用。

2) You can use try-catch : 2)您可以使用try-catch

try {
  var readFile = ReadFile();
} catch(e) {
  console.log(e);
}

3) Or use callback for error: 3)或使用回调的错误:

function ReadFile(options, errorCallback) {
  /**...**/
  if (!options.okay) {
    errorCallback( new Error('Forced crash') );
    return;
  }
  /**...**/ 
}

My thought is the 'error' event is emitted even before the stream object finished being created. 我的想法是,甚至在流对象创建完成之前就发出“错误”事件。 As a result node doesn't find the 'error' listener that you attached since it's not yet created and throws it as Unhandled 'error' event . 结果,节点未找到您附加的“错误”侦听器,因为它尚未创建,并将其作为Unhandled 'error' event抛出。

One solution would be delay the event emit using setImmediate . 一种解决方案是使用setImmediate延迟事件发出。 Then it'll create the stream object and bind the error listeners first before emitting the error : 然后,它将创建流对象,并在发出错误之前首先绑定错误侦听器:

 if (!options.okay) {
    setImmediate(function(){ 
      self.emit('error', new Error('Forced crash')); 
    });
    return;
  }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM