草庐IT

javascript - Node.js UnhandledPromiseRejectionWarning 即使在捕获它之后

coder 2025-01-11 原文

我正在使用具有新的 async/await 功能的 Node 7.2.1。我也像这样将 Native ES6 Promises 与 mongoose 一起使用 -

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 block 中打印出来,但 Node.js 仍然说错误消息未处理.

为什么即使发现了同样的错误,它仍然这么说?

更新- 感谢@dvlsg 和@Bergi,该错误已在 4.7.5 版本中修复

最佳答案

mongoose aggregate 如何与 async/await 一起玩,肯定有一些奇怪的地方。对我来说似乎是一个错误。如果是,绝对应该报告给 mongoose。

值得庆幸的是,有一个简单的解决方法:

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

添加显式 .exec() 允许我按预期捕获聚合管道错误。


我认为增加这里困惑的潜在问题是有一个额外的 Promise 被拒绝并且没有被处理。因为从技术上讲,您在这里正确处理预期的拒绝。否则您将看不到 Printing error = ... 被记录。

这是我认为正在发生的事情 --

  • 等待 User.aggregate()
  • Aggregate#then() 通过 awaitthenables 一起调用(我认为)
  • Aggregate#exec()Aggregate#then() 内部调用
  • Aggregate#exec() 中的新Promisecreated , 和 will be rejected
    • This 是未处理的 Promise,我相信。
  • 由于从 Aggregate#then()Aggregate#exec() 提供了回调,Aggregate# 中的 Error exec() 将是 provided to the callback
  • Aggregate#then() 的回调中,一个新的 created Promise 被拒绝
    • 我相信这个 Promise 是按预期处理的,因为它是 Aggregate#then()
    • 的返回值

我想我可以通过注释掉 this line 来证实我的怀疑在 mongoose Aggregate 定义中。这将防止未处理的拒绝处理程序被命中。顺便说一下,我并不是建议这样做。这只是额外的证据,而不是解决方案,因为现在我只有一个未被拒绝的 Promise 浮现。


这是一种在自包含代码中重现未捕获拒绝的最小方法,与 node --harmony-async-await 一起运行(在 Node 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();

关于javascript - Node.js UnhandledPromiseRejectionWarning 即使在捕获它之后,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41247012/

有关javascript - Node.js UnhandledPromiseRejectionWarning 即使在捕获它之后的更多相关文章

  1. ruby - 即使失败也继续进行多主机测试 - 2

    我已经构建了一些serverspec代码来在多个主机上运行一组测试。问题是当任何测试失败时,测试会在当前主机停止。即使测试失败,我也希望它继续在所有主机上运行。Rakefile:namespace:specdotask:all=>hosts.map{|h|'spec:'+h.split('.')[0]}hosts.eachdo|host|begindesc"Runserverspecto#{host}"RSpec::Core::RakeTask.new(host)do|t|ENV['TARGET_HOST']=hostt.pattern="spec/cfengine3/*_spec.r

  2. ruby - 如何让Ruby捕获线程中的语法错误 - 2

    我正在尝试使用ruby​​编写一个双线程客户端,一个线程从套接字读取数据并将其打印出来,另一个线程读取本地数据并将其发送到远程服务器。我发现的问题是Ruby似乎无法捕获线程内的错误,这是一个示例:#!/usr/bin/rubyThread.new{loop{$stdout.puts"hi"abc.putsefsleep1}}loop{sleep1}显然,如果我在线程外键入abc.putsef,代码将永远不会运行,因为Ruby将报告“undefinedvariableabc”。但是,如果它在一个线程内,则没有错误报告。我的问题是,如何让Ruby捕获这样的错误?或者至少,报告线程中的错误?

  3. ruby-on-rails - 无法在 Rails 助手中捕获 block 的输出 - 2

    我在使用自定义RailsFormBuilder时遇到了问题,从昨天晚上开始我就发疯了。基本上我想对我的构建器方法之一有一个可选block,以便我可以在我的主要content_tag中显示其他内容。:defform_field(method,&block)content_tag(:div,class:'field')doconcatlabel(method,"Label#{method}")concattext_field(method)capture(&block)ifblock_given?endend当我在我的一个Slim模板中调用该方法时,如下所示:=f.form_field:e

  4. 即使安装了 gem,Ruby 也找不到所需的库 - 2

    我花了几天时间尝试安装ruby​​1.9.2并让它与gems一起工作:-/我最终放弃了我的MacOSX10.6机器,下面是我的Ubuntu机器上的当前状态。任何建议将不胜感激!#rubytest.rb:29:in`require':nosuchfiletoload--mongo(LoadError)from:29:in`require'fromtest.rb:1:in`'#cattest.rbrequire'mongo'db=Mongo::Connection.new.db("mydb")#gemwhichmongo/usr/local/rvm/gems/ruby-1.9.2-p0/g

  5. ruby-on-rails - 使用 javascript 更改数据方法不会更改 ajax 调用用户的什么方法? - 2

    我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的

  6. ruby - 在 ruby​​ 中生成一个进程,捕获 stdout,stderr,获取退出状态 - 2

    我想从ruby​​rake脚本运行一个可执行文件,比如foo.exe我希望将foo.exe的STDOUT和STDERR输出直接写入我正在运行rake任务的控制台.当进程完成时,我想将退出代码捕获到一个变量中。我如何实现这一目标?我一直在玩backticks、process.spawn、system但我无法获得我想要的所有行为,只有部分更新:我在Windows上,在标准命令提示符下,而不是cygwin 最佳答案 system获取您想要的STDOUT行为。它还返回true作为零退出代码,这可能很有用。$?填充了有关最后一次system调

  7. ruby - 捕获 Ruby Logger 输出以进行测试 - 2

    我有一个像这样的ruby​​类:require'logger'classTdefdo_somethinglog=Logger.new(STDERR)log.info("Hereisaninfomessage")endend测试脚本行如下:#!/usr/bin/envrubygem"minitest"require'minitest/autorun'require_relative't'classTestMailProcessorClasses当我运行这个测试时,out和err都是空字符串。我看到消息打印在stderr上(在终端上)。有没有办法让Logger和capture_io一起玩得

  8. ruby - Capistrano 中的执行、测试和捕获命令有什么区别? - 2

    关于SSHkit-Github它说:Allbackendssupporttheexecute(*args),test(*args)&capture(*args)来自SSHkit-Rubydoc,我明白execute实际上是test的别名?test之间有什么区别?,execute,capture在Capistrano/SSHKit中我应该什么时候使用? 最佳答案 执行只是执行命令。使用非0退出引发错误。测试方法的行为与execute完全相同,但是它返回bool值(true如果命令以0退出,而false否则)。它通常用于控制任务中的流程

  9. ruby - 如何捕获 ruby​​ 中的所有异常? - 2

    我们如何捕获或/和处理ruby​​中所有未处理的异常?例如,这样做的动机可能是将某种异常记录到不同的文件或发送电子邮件给系统管理。在Java中我们会做Thread.setDefaultUncaughtExceptionHandler(UncaughtExceptionHandlerex);在Node.js中process.on('uncaughtException',function(error){/*code*/});在PHP中register_shutdown_function('errorHandler');functionerrorHandler(){$error=error_

  10. ruby - 正则表达式 - 保存重复捕获的组 - 2

    这就是我做的a="%span.rockets#diamonds.ribbons.forever"a=a.match(/(^\%\w+)([\.|\#]\w+)+/)putsa.inspect这是我得到的#这就是我想要的#帮助?我尝试过但失败了:( 最佳答案 通常,您不能获得任意数量的捕获组,但如果您使用扫描,您可以为您想要捕获的每个标记获得一个匹配:a="%span.rockets#diamonds.ribbons.forever"a=a.scan(/^%\w+|\G[.|#]\w+/)putsa.inspect["%span","

随机推荐