javascript - 如何从异步 mongoose 中间件的 post 钩子抛出错误
从异步 Mongoose 中间件 post 钩子 抛出错误的正确方式是什么?
代码示例
以下 TypeScript 代码使用 mongoose 的 post init 事件来运行一些检查,这些检查会在每当函数从 mongoDb 获取文档时触发。这个示例中的 postInit() 函数正在执行一些后台检查。它在某些情况下会失败,然后返回 Promise.reject('Error!');
schema.post('init', function (this: Query<any>, doc: any) {
return instance.postInit(this, doc)
.catch( err => {
return err;
});
});
钩子运行良好。例如,以下代码会触发钩子:
MyMongooseModel.findOne({ _id : doc.id}, (err, o : any) => {
console.log(o);
});
然而,如果 postInit() 失败,错误不会传回调用函数。相反,将返回文档。
预期行为
我正在寻找将此错误传递给调用函数的正确方法。如果后台检查失败,调用函数不应该获取到文档。
我尝试了不同的方法来引发这个错误。例如:throw new Error('Error');。然而,这会导致 UnhandledPromiseRejectionWarning,并且仍然返回文档。
答案#1
我是 Mongoose 的维护者。不幸的是,init() 钩子是同步的,而我们在文档中对此说明得不够好。我们已经在 GitHub 上开了一个 issue,并将尽快添加相关文档。在 post('init') 中报告错误的唯一方法是 throw 它。
const assert = require('assert');
const mongoose = require('mongoose');
mongoose.set('debug', true);
const GITHUB_ISSUE = `init`;
const connectionString = `mongodb://localhost:27017/${ GITHUB_ISSUE }`;
const { Schema } = mongoose;
run().then(() => console.log('done')).catch(error => console.error(error.stack));
async function run() {
await mongoose.connect(connectionString);
await mongoose.connection.dropDatabase();
const schema = new mongoose.Schema({
name: String
});
schema.post('init', () => { throw new Error('Oops!'); });
const M = mongoose.model('Test', schema);
await M.create({ name: 'foo' });
await M.findOne(); // Throws "Oops!"
}
这是因为 Mongoose 假设 init() 在内部是同步的。
答案#2
在这个post init hook方法中,你只会收到一个doc:
Document.prototype.init()
参数 doc «Object» 由 mongo 返回的文档 初始化文档而不使用 setter 或标记任何内容已修改。
在文档从mongodb返回后内部调用。
Mongoose 文档:初始化钩子文档
要触发一个错误,你需要一个 done 或 next 方法:
帖子中间件
后置中间件在钩住的方法及其所有前置中间件完成后执行。后置中间件不会直接接收流程控制,例如,不会传递 next 或 done 回调给它。后置钩子是一种为这些方法注册传统事件监听器的方式。
Mongoose 文档:后置中间件
如果你只想知道你的调用中是否发生了错误,请改成这个:
MyMongooseModel.findOne({ _id : doc.id}, (err, o : any) => {
if(err) {
throw new Error(err);
}
console.log(o);
});
如果你想传播错误,一种选择是使用 pre 钩子方法:
schema.pre('save', function(next) {
const err = new Error('something went wrong');
// If you call `next()` with an argument, that argument is assumed to be
// an error.
next(err);
});
schema.pre('save', function() {
// You can also return a promise that rejects
return new Promise((resolve, reject) => {
reject(new Error('something went wrong'));
});
});
schema.pre('save', function() {
// You can also throw a synchronous error
throw new Error('something went wrong');
});
schema.pre('save', async function() {
await Promise.resolve();
// You can also throw an error in an `async` function
throw new Error('something went wrong');
});
示例错误处理:错误处理
