是什么?
.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 。
參考:
