是什么?
.exec()
和 .save()
一样是 Mongoose 的异步操作,都返回一个 thenable 。
怎么用?
我们先定义一个 query
对象: const query = MyModel.findOne({})
,接下来我们一般会这么使用:
query.then(doc => {...})
// or
const doc = await query.exec()
有什么区别?
-
query 本身并不是 Promise 对象,它只是实现了
.then
和.catch
方法便于异步操作; -
.exec()
返回了一个真正的 Promise 对象。
但 query 提供了 .then
方法,我们一样可以使用 async/await :
const doc = await query
// or
const doc = await query.exec()
以上两种写法已近乎一致,而事实上它们在功能执行上也 完全一致 。
是否需要使用 .exec()
?
官方建议使用 .exec()
,因为它在使用 async/await 时提供了更好的堆栈跟踪。
以官方示例:
const doc = await Band.findOne({ name: "Guns N' Roses" }); // works
const badId = 'this is not a valid id';
try {
await Band.findOne({ _id: badId });
} catch (err) {
// Without `exec()`, the stack trace does **not** include the
// calling code. Below is the stack trace:
//
// CastError: Cast to ObjectId failed for value "this is not a valid id" at path "_id" for model "band-promises"
// at new CastError (/app/node_modules/mongoose/lib/error/cast.js:29:11)
// at model.Query.exec (/app/node_modules/mongoose/lib/query.js:4331:21)
// at model.Query.Query.then (/app/node_modules/mongoose/lib/query.js:4423:15)
// at process._tickCallback (internal/process/next_tick.js:68:7)
err.stack;
}
try {
await Band.findOne({ _id: badId }).exec();
} catch (err) {
// With `exec()`, the stack trace includes where in your code you
// called `exec()`. Below is the stack trace:
//
// CastError: Cast to ObjectId failed for value "this is not a valid id" at path "_id" for model "band-promises"
// at new CastError (/app/node_modules/mongoose/lib/error/cast.js:29:11)
// at model.Query.exec (/app/node_modules/mongoose/lib/query.js:4331:21)
// at Context.<anonymous> (/app/test/index.test.js:138:42) <--- here
// at process._tickCallback (internal/process/next_tick.js:68:7)
err.stack;
}
可以看到,使用 .exec()
时能直接追踪到异常位置: index.test.js:138:42
。
参考: