即使在捕获之后,Node.js仍然处于未处理状态

我正在使用节点7.2.1与新的asynchronous/等待function。 我也用这样的mongoose使用本地ES6诺言 –

const mongoose = require('mongoose'); mongoose.Promise = global.Promise; 

我的代码stream是这样的 –

 async function getFollowers(){ try { const followers = await User.getFollowersFromMongo(req.params.userId); res.send(followers); } catch (err) { winston.error('Printing Error = ', err); res.status(400).send({success: false, error: err}); } } UserSchema.statics.getFollowersFromMongo = async(userId) => { try { let aggregateQuery = []; //some syntactical error in mongo query to produce exception const followers = await User.aggregate(aggregateQuery); return followers.map(follower => follower.followerData); } catch (err) { return Promise.reject(err); } }; 

这段代码工作得很好。 出现错误时会出现问题。 所以我特意修改了我的mongoose查询,这样MongoDB就会抛出一个错误。

现在,MongoDB,如预期的抛出一个错误,完全被我的代码捕获,并返回给客户端400错误代码。

问题是即使错误(故意的)被我抓住了, Node.js仍然给了我这个警告 –

 error: Printing Error = MongoError: path option to $unwind stage should be prefixed with a '$': followerData at Function.MongoError.create (/home/node_modules/mongodb-core/lib/error.js:31:11) at /home/node_modules/mongodb-core/lib/connection/pool.js:483:72 at authenticateStragglers (/home/node_modules/mongodb-core/lib/connection/pool.js:429:16) at Connection.messageHandler (/home/node_modules/mongodb-core/lib/connection/pool.js:463:5) at Socket.<anonymous> (/home/node_modules/mongodb-core/lib/connection/connection.js:317:22) at emitOne (events.js:96:13) at Socket.emit (events.js:188:7) at readableAddChunk (_stream_readable.js:176:18) at Socket.Readable.push (_stream_readable.js:134:10) at TCP.onread (net.js:551:20) GET /user/385/followers 400 39.868 ms - 263 (node:10158) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): MongoError: path option to $unwind stage should be prefixed with a '$': followerData (node:10158) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code. 

由于可以看到我的请求已经返回了400状态,而且我的错误日志也是从初始方法的catch块中打印出来的,但是Node.js仍然在说错误消息没有被处理。

为什么即使在发现相同的错误之后,也是这样说的?

更新 –感谢@dvlsg和@Bergi,这个bug在4.7.5版本中得到了修复

看起来似乎有什么奇怪的mongoose聚合如何与asynchronous/等待。 好像是一个bug,对我来说。 如果是的话,一定要报告mongoose。

谢天谢地,有一个简单的工作:

 const followers = await User.aggregate(aggregateQuery).exec(); 

添加明确的.exec()允许我按预期捕获聚合pipe道错误。


我认为这里增加了一个混乱的根本问题是,有一个额外的Promise ,其中正在被拒绝,而不是处理。 因为在技术上,你正在处理预期的拒绝。 否则,你不会看到Printing error = ...被logging。

这是我相信正在发生的事情 –

  • await User.aggregate()
  • Aggregate#then()通过awaitthenables (我认为)
  • Aggregate#exec()Aggregate#then()内部调用Aggregate#then()
    • 请注意, 提供给exec() 的callback exec()
  • Aggregate#exec()Promise被创build ,并被拒绝
    • 我相信是未处理的Promise
  • 由于callback是从Aggregate#then()提供给Aggregate#exec() Aggregate#then()Aggregate#exec()Error将被提供给callback Aggregate#exec()
  • Aggregate#then()的callback中,新创build的 Promise被拒绝
    • 我相信这个Promise是按预期处理的,因为它是来自Aggregate#then()的回报, Aggregate#then()

我想我可以通过在mongooseAggregate定义中注释这一行来证实我的怀疑。 这将防止未处理的拒绝处理程序被击中。 顺便说一下,我并不打算这样做。 这只是额外的证据,而不是一个解决scheme,因为现在我只是有一个不受欢迎的Promise浮出水面。


这是一个最小化的方法来重现在一个自包含的代码中的未被捕获的拒绝,要与node --harmony-async-await一起运行(在节点v7.2.1上testing)

 const mongoose = require('mongoose'); mongoose.Promise = global.Promise; mongoose.connect('mongodb://localhost/temp'); const userSchema = new mongoose.Schema({ name: 'string' }); const User = mongoose.model('User', userSchema); async function run() { try { await User.aggregate([]); } catch (err) { console.log('caught expected error:', err); } } run();