Node.js UnhandledPromiseRejectionWarning 即使在捕获它之后
Posted
技术标签:
【中文标题】Node.js UnhandledPromiseRejectionWarning 即使在捕获它之后【英文标题】:Node.js UnhandledPromiseRejectionWarning even after catching it 【发布时间】:2017-05-05 22:42:49 【问题描述】:我正在使用具有新 async/await 功能的 Node 7.2.1。我也在像这样使用带有猫鼬的 Native ES6 Promises -
const mongoose = require('mongoose');
mongoose.Promise = global.Promise;
我的代码流程是这样的——
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,该错误已在版本 4.7.5 中得到修复
【问题讨论】:
我猜是因为你用 try/catch 而不是 .catch() 来捕捉它。 @KevinB 但这不是 async/await 处理错误的方式吗? 相关:***.com/questions/40500490/… 不使用.catch()
似乎不是问题。 This 是另一个使用相同方法的示例,它不会产生 unhandled
堆栈跟踪。
此示例没有未处理错误的原因是因为caller1
将catch
来自Promise.reject(err)
来自caller2
。
【参考方案1】:
mongoose 聚合如何使用 async/await 显然有些奇怪。对我来说,这似乎是一个错误。如果是的话,一定要报告给猫鼬。
谢天谢地,有一个简单的解决方法:
const followers = await User.aggregate(aggregateQuery).exec();
添加显式 .exec()
可以让我按预期捕获聚合管道错误。
我认为增加混乱的根本问题是有一个额外的Promise
漂浮在周围,被拒绝且未处理。因为从技术上讲,您 正确地处理了这里的预期拒绝。否则你不会看到 Printing error = ...
被记录。
这就是我认为正在发生的事情--
你await User.aggregate()
Aggregate#then()
是通过 await
与 thenables
一起调用的(我认为)
Aggregate#exec()
在内部由 Aggregate#then()
调用
注意a callback is provided 到exec()
Aggregate#exec()
内部的新Promise
是created,和will be rejected
这个是未处理的Promise
,我相信。
由于从Aggregate#then()
向Aggregate#exec()
提供了回调,所以Aggregate#exec()
中的Error
将是provided to the callback
在Aggregate#then()
的回调中,新的created Promise
被拒绝
我相信这个Promise
会按预期处理,因为它是来自Aggregate#then()
的返回
我想我可以通过注释掉猫鼬Aggregate
定义中的this line 来证实我的怀疑。这将防止未处理的拒绝处理程序被击中。顺便说一句,我并不是建议这样做。这只是额外的证据,而不是解决方案,因为现在我只有一个未被拒绝的Promise
。
这是一种在自包含代码中重现未被捕获的拒绝的最小方法,使用 node --harmony-async-await
运行(在节点 v7.2.1
上测试)
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();
【讨论】:
如果是这种情况,绝对应该将它作为一个错误报告给mongoose。 感谢源代码的链接,正如我所怀疑的那样。解决方法应该是将then
方法更改为简单的function(onfulfill, onreject) return this.exec().then(onfulfill, onreject);
、avoiding the Promise
constructor antipattern,这会通过exec
回调不必要地创建第二个promise。您要打开 GH 问题吗?
当然可以。
问题可用here。
是的,在查询末尾应用 .exec()
不会产生错误。我会关注 github 问题,如果你的推理被证明是正确的,那么我很乐意接受这个答案。以上是关于Node.js UnhandledPromiseRejectionWarning 即使在捕获它之后的主要内容,如果未能解决你的问题,请参考以下文章