Promise
內建 Promise
Mongoose 的非同步操作,例如 .save()
和查詢,會傳回 thenable 物件。這表示你可以執行 MyModel.findOne({}).then()
之類的操作,如果你使用 async/await,則可以使用 await MyModel.findOne({}).exec()
。
你可以在 API 文件 中找到特定操作的傳回類型。你也可以閱讀更多關於 Mongoose 中的 Promise 的資訊。
const gnr = new Band({
name: 'Guns N\' Roses',
members: ['Axl', 'Slash']
});
const promise = gnr.save();
assert.ok(promise instanceof Promise);
promise.then(function(doc) {
assert.equal(doc.name, 'Guns N\' Roses');
});
查詢不是 Promise
Mongoose 查詢不是 Promise。它們為了方便 co 和 async/await 而具有 .then()
函式。如果你需要一個功能完整的 Promise,請使用 .exec()
函式。
const query = Band.findOne({ name: 'Guns N\' Roses' });
assert.ok(!(query instanceof Promise));
// A query is not a fully-fledged promise, but it does have a `.then()`.
query.then(function(doc) {
// use doc
});
// `.exec()` gives you a fully-fledged promise
const promise = Band.findOne({ name: 'Guns N\' Roses' }).exec();
assert.ok(promise instanceof Promise);
promise.then(function(doc) {
// use doc
});
查詢是 thenable
儘管查詢不是 Promise,但查詢是 thenable。這表示它們具有 .then()
函式,因此你可以將查詢作為 Promise 使用,無論是使用 Promise 鏈還是 async await。
Band.findOne({ name: 'Guns N\' Roses' }).then(function(doc) {
// use doc
});
應該將 exec()
與 await
一起使用嗎?
有兩種將 await
與查詢一起使用的替代方法
await Band.findOne();
await Band.findOne().exec();
就功能而言,這兩者是等效的。但是,我們建議使用 .exec()
,因為這樣可以提供更好的堆疊追蹤。
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)
// at process._tickCallback (internal/process/next_tick.js:68:7)
err.stack;
}
想學習如何檢查你最喜歡的 npm 模組是否與 async/await 一起使用,而無需從 Google 和 Stack Overflow 中拼湊出矛盾的答案嗎?《Mastering Async/Await》的第 4 章解釋了確定 React 和 Mongoose 等框架是否支援 async/await 的基本原則。 取得你的副本!
