Node.js 为什么Express';从可读流发出时默认错误处理程序捕获错误?

Node.js 为什么Express';从可读流发出时默认错误处理程序捕获错误?,node.js,express,stream,streaming,Node.js,Express,Stream,Streaming,我使用命令行Express stream\u test安装了一个样板快速应用程序。我将默认的/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 readFi

我使用命令行
Express stream\u test
安装了一个样板快速应用程序。我将默认的
/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
只是
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;
那很好用。调用路由时,它会将
傲慢和偏见.txt的内容输出到屏幕

但假设某些要求未得到满足,我想在流式传输数据之前抛出一个错误:

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

}
这会在
选项时抛出一个错误
强制崩溃。
正确
错误
。我希望在监听
错误时捕获我的
index.js
路由中的错误。但处理程序从不执行。令我非常惊讶的是,
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
    });
  });
}
这让我快发疯了。错误是如何结束的?为什么事件侦听器没有捕捉到它?

1)当您发出
错误时,ReadFile将不返回任何内容,以及路由器模块之外的最近错误陷阱,然后在调用ReadFile后返回

2) 您可以使用
try catch

try {
  var readFile = ReadFile();
} catch(e) {
  console.log(e);
}
3) 或对错误使用回调:

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

我的想法是,即使在流对象完成创建之前,也会发出“error”事件。因此,节点找不到您附加的“错误”侦听器,因为尚未创建该侦听器,并将其作为未处理的“错误”事件抛出

一种解决方案是使用
setImmediate
延迟事件发出。然后,它将创建流对象并在发出错误之前首先绑定错误侦听器:

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