为什么快速的默认error handling程序捕获从可读stream发射时的错误?

我使用命令行express stream_test安装了样板快速应用程序。 我用下面的/routes/index.jsreplace了默认的/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; 

这工作完全正常。 调用路由时,将pride_and_prejudice.txt的内容输出到屏幕上。

但是,让我们说一些要求不符合,我想在stream数据之前抛出一个错误:

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

这会引发错误Forced crash.options.okayfalse 。 我希望在侦听错误时捕获index.js路由中的error 。 但处理程序从不执行。 令我惊讶的是, app.js的默认error handling程序正在捕获错误:

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

这使我疯狂。 错误如何最终在那里? 为什么事件监听器没有捕捉到它?

我的想法是,即使在stream对象完成创build之前,“错误”事件也会被发射出去。 因为节点没有find你附加的“错误”侦听器,因为它尚未创build,并将其作为Unhandled 'error' event抛出。

一种解决scheme是使用setImmediate延迟事件发射。 然后它会在发出错误之前创buildstream对象并绑定错误侦听器:

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

1)当您发出error ,ReadFile不会返回任何内容,也不会返回路由器模块外部最近的错误陷阱,然后在调用ReadFile之后调用它。

2)你可以使用try-catch

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

3)或使用callback错误:

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