我正在使用具有新 async/await 功能的Node 7.2.1。我也在像这样的 Mongoose 一起使用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版中修复。

最佳答案

Mongoose 聚合如何在异步/等待中发挥作用似乎确实有些奇怪。对我来说,好像是个 bug 。如果是这样,绝对应该将其报告给 Mongoose 。

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

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

添加显式的.exec()可以使我按预期捕获总的管道错误。

我认为,这里增加了困惑的根本问题是,周围有另外一个Promise float ,该Printing error = ...被拒绝并且未被处理。因为从技术上讲,您在这里正确地处理了预期的拒绝。否则,您将不会看到正在记录的await User.aggregate()

我相信这是正在发生的事情-
  • Aggregate#then()
  • await通过与thenables一起工作的Aggregate#exec()调用(我认为)
  • Aggregate#then()在内部由exec()调用
  • 注意a callback is providedPromise
  • Aggregate#exec()中的新Promisecreatedwill be rejected
  • 我相信这是未处理的Aggregate#exec()
  • 由于提供了从Aggregate#then()Error的回调,因此Aggregate#exec()中的Aggregate#then()将为provided to the callback
  • Promise的回调中,新的created Promise被拒绝
  • 我相信此Aggregate#then()已按预期方式处理,因为它是Aggregate的返回

  • 我想我可以通过在 Mongoose Promise定义中注释掉this line来证实我的怀疑。这将防止未处理的拒绝处理程序被击中。顺便说一句,我并不是建议这样做。那只是额外的证据,而不是解决方案,因为现在我只剩下一个未经拒绝的node --harmony-async-await了。

    这是一种最小的方法,可以用v7.2.1(在 Node ojit_code上测试)运行,以自包含的代码重现未捕获的拒绝。
    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();
    

    09-30 13:40
    查看更多