Узел.JS UnhandledPromiseRejectionWarning даже после его ловли
Я использую узел 7.2.1 с новым async / await характеристика. Я также использую родные обещания ES6 с мангустой, как это -
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);
}
};
этот код работает абсолютно нормально. Проблема возникает, когда возникает какая-то ошибка. Поэтому я намеренно изменил свой мангуста запрос так что MongoDB выдаст ошибку.
Теперь MongoDB, как и ожидалось, выдает ошибку, которая отлично пойманный моим кодом и возвращенный клиенту с кодом ошибки 400.
проблема в том, что, хотя ошибка(преднамеренная) была поймана мной,узел.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 исходного метода, но узел.js о том, что сообщение об ошибке не обрабатываются.
почему говорит ли он это даже после того, как та же ошибка была поймана?
обновление - благодаря @dvlsg и @Bergi, ошибка была исправлена в версии 4.7.5
1 ответов
определенно, кажется, что-то странное с тем, как Mongoose aggregate играет с async/await. Мне кажется, это жук. Если это так, то об этом обязательно следует сообщить Мангусту.
к счастью, есть легко обойти:
const followers = await User.aggregate(aggregateQuery).exec();
добавление явного .exec()
позволяет мне поймать ошибку aggregate pipeline, как ожидалось.
я думаю, что основная проблема, добавляющая к путанице здесь, заключается в том, что есть дополнительный Promise
плавающий вокруг, который отклоняется и не обрабатывается. Потому что технически, ты are обработка ожидаемого отклонения здесь правильно. Иначе вы бы этого не увидели!--4--> журнал.
вот что я думаю, происходит...
- вы
await User.aggregate()
-
Aggregate#then()
вызывается черезawait
работает сthenables
(Я думаю) -
Aggregate#exec()
вызывается внутриAggregate#then()
- обратите внимание, что обратный вызов предусмотренного до
exec()
- обратите внимание, что обратный вызов предусмотренного до
- новая
Promise
внутриAggregate#exec()
is создано и будут отклонены-
этой - это необработанное
Promise
, Я считаю.
-
этой - это необработанное
- так как обратный вызов предоставляется
Aggregate#exec()
СAggregate#then()
наError
внутриAggregate#exec()
будет при условии обратного вызова - внутри функции обратного вызова в
Aggregate#then()
, недавно созданоPromise
отклонено- я верю в это
Promise
обрабатывается как ожидалось, так как это возврат отAggregate#then()
- я верю в это
я думаю, что могу подтвердить свои подозрения, комментируя эта строка в мангуста Aggregate
определение. Это предотвратит попадание обработчика необработанного отклонения. Между прочим, я не собираюсь этого делать. Это просто дополнительные доказательства, а не решение, так как теперь у меня просто есть unrejected 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();