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ではありません.then() 関数が co と async/await を便利に使用できます。完全な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チェイニングまたは async awaitでクエリをPromiseとして使用できます。

Band.findOne({ name: 'Guns N\' Roses' }).then(function(doc) {
  // use doc
});

exec()await で使用するべきでしょうか?

クエリで await を使用するために2つの方法があります。

  • await Band.findOne();
  • await Band.findOne().exec();

機能に関して言えば、これら2つは同等です。ただし、 .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モジュールが非同期で待機なしで動作するかどうかを、GoogleやStack Overflowからの矛盾した回答を組み合わせることなしに確認する方法を知りたいですか?Mastering Async/Awaitの第4章では、ReactやMongooseなどのフレームワークがasync/awaitをサポートするかどうかを確認するための基本原則について説明します。今すぐ手に入れましょう!

Mastering Async/Await