#node.js #express #mongoose
Вопрос:
Я пробую различные способы обработки ошибок. Если у меня есть настройка для добавления нового документа, и я хочу проверить, является ли имя уникальным, я делаю что-то вроде
router.route('/addSomething').post(async (req,res,next) => {
await Document.findOne(
{name: req.body.name}, // search parameter
(error,doc) = { // callback
if(error) return next(error) // pass system generated error to next() and exit route
else if (doc) return next(new Error("This name already exists")) // pass my own error to next() and exit route
})
// everything from now on shouldn't happen
await Document.save() etc...
Проблема, с которой я сталкиваюсь, заключается в том, что функция маршрута продолжается, даже если вернулась ошибка (я понимаю, что это связано с тем, что оператор return возвращается только из функции обратного вызова).
Я ищу элегантный способ обработки ошибок mongoose/mongodb и выхода из функции в момент ошибки, не помещая блоки try/catch повсюду.
Ответ №1:
Когда вы возвращаетесь next(...)
в свою функцию обратного вызова, вы на самом деле возвращаетесь не из остальной части своего кода, а только внутри этой функции. Чтобы устранить эту проблему, я добавил continue()
функцию внутри вашего кода для продолжения входящего HTTP-запроса.
router.route('/addSomething').post(async (req, res, next) => {
await Document.findOne(
{ name: req.body.name }, // search parameter
(error, doc) => { // callback
if (error) return next(error) // pass system generated error to next() and exit route
else if (doc) return next(new Error("This name already exists")) // pass my own error to next() and exit route
continue(); // Call the continue function if function isn't already returned
}
);
function continue() { // Add a continue function
// Continue your code
await Document.save();
// ...
}
});
Комментарии:
1. Это довольно простое решение, но может привести к беспорядку, если в коде будет несколько функций обратного вызова. Мне понадобилось бы continue2(), continue3 () и т. Д. Для обработки последующих экземпляров обратного вызова
2. @EdwardMartin Верно, однако единственный другой способ сделать это-обернуть весь ваш код в обратный вызов, тогда вы вызовете ад обратного вызова.
Ответ №2:
Рассмотрите возможность использования util.promisify
, чтобы избавиться от обратного вызова:
router.route('/addSomething').post(async (req, res, next) => {
try {
var doc = await util.promisify(Document.findOne)(
{ name: req.body.name } // search parameter
);
} catch(error) {
return next(error); // pass system generated error to next() and exit route
}
if (doc) return next(new Error("This name already exists")); // pass my own error to next() and exit route
// everything from now on shouldn't happen
await Document.save() etc...
});
Комментарии:
1. Спасибо за ваше предложение. Document.findOne() уже возвращает обещание. Я могу использовать . затем и .методы улова, но предпочел бы не
2. Если вы используете
await
, вам не нужно использовать.then
и.catch
. Строка 3 моего ответа тогда просто становитсяvar doc = await Document.findOne(
.3. Тогда вопрос в том, как я могу обработать любую ошибку из этого, не заключая ее в блок try/catch. В идеале я мог бы сказать var [ошибка,doc] = ожидание документа.findOne( аналогично обратному вызову, но я знаю, что это не сработает!
4. Не вижу, как вы могли бы справиться с ошибкой, если бы не использовали ни
catch
то, ни.catch
другое .5. Они могут быть обработаны с помощью обратного вызова findOne: .findOne({},(ошибка,документ)=>…), но проблема в том, что я не могу выйти из внешней функции в рамках этого обратного вызова