文档菜单
文档首页
/ / /
Node.js 驱动程序
/

承诺

本页内容

  • 概述
  • 承诺
  • 等待
  • 运行时考虑

Node.js 驱动程序使用异步 JavaScript API 与您的 MongoDB 集群通信。

异步 JavaScript 允许您在不等待处理线程空闲时执行操作。这有助于防止您的应用程序在执行长时间运行的操作时变得无响应。有关异步 JavaScript 的更多信息,请参阅 MDN 网络文档中的异步 JavaScript.

本节描述了承诺,您可以使用 Node.js 驱动程序使用它们来访问对 MongoDB 集群的方法调用结果。

承诺是由异步方法调用返回的对象,允许您访问它们包装的操作最终成功或失败的信息。如果操作仍在运行,承诺处于 挂起 状态,如果操作成功完成,则处于 已解决 状态,如果操作抛出异常,则处于 拒绝 状态。有关承诺和相关术语的更多信息,请参阅 MDN 文档中的 承诺。

大多数与您的 MongoDB 集群通信的驱动程序方法,例如 findOneAndUpdate()countDocuments(),返回承诺对象,并且已经包含处理操作成功或失败逻辑。

您可以通过附加 then() 方法来定义自己的逻辑,该逻辑在承诺达到 已解决拒绝 状态时执行。then() 的第一个参数是在承诺达到 已解决 状态时调用的方法,而可选的第二个参数是在它达到 拒绝 状态时调用的方法。then() 方法返回一个承诺,您可以附加更多的 then() 方法。

当您将一个或多个 then() 方法附加到承诺时,每个调用都会将其执行结果传递给下一个调用。这种模式称为 承诺链式调用。以下代码示例通过附加单个 then() 方法演示了承诺链式调用的示例。

collection
.updateOne({ name: "Mount McKinley" }, { $set: { meters: 6190 } })
.then(
res => console.log(`Updated ${res.result.n} documents`),
err => console.error(`Something went wrong: ${err}`),
);

要处理只到 拒绝 状态的承诺转换,请使用 catch() 方法而不是将第一个参数传递为 nullthen()catch() 方法接受一个回调,当承诺转换到 拒绝 状态时执行。

catch() 方法通常附加在承诺链的末尾,以处理抛出的任何异常。以下代码示例演示了将 catch() 方法附加到承诺链末尾。

deleteOne({ name: "Mount Doom" })
.then(result => {
if (result.deletedCount !== 1) {
throw "Could not find Mount Doom!";
}
return new Promise((resolve, reject) => {
...
});
})
.then(result => console.log(`Vanquished ${result.quantity} Nazgul`))
.catch(err => console.error(`Fatal error occurred: ${err}`));

注意

驱动程序中的某些方法,如find(),返回一个Cursor而不是Promise。要确定每个方法返回的类型,请参阅Node.js API文档。

如果您正在使用async函数,您可以在Promise上使用await运算符以暂停进一步执行,直到Promise达到已解决拒绝状态并返回。由于await运算符等待Promise的解决,因此您可以用它来代替Promise链,按顺序执行您的逻辑。以下代码片段使用await来执行与第一个Promise链示例相同的逻辑。

async function run() {
...
try {
res = await myColl.updateOne(
{ name: "Mount McKinley" },
{ $set: { meters: 6190 } },
);
console.log(`Updated ${res.result.n} documents`);
} catch (err) {
console.error(`Something went wrong: ${err}`);
}
}

有关更多信息,请参阅MDN上关于await。

在使用 async 方法时,一个常见的错误是忘记在 Promise 上使用 await 操作符来获取结果的值,而不是 Promise 对象。考虑以下示例,其中我们使用 hasNext() 迭代游标,它返回一个解析为表示是否存在更多结果的布尔值的 Promise,以及 next(),它返回一个解析为游标所指向的下一个条目的 Promise。

async function run() {
...
// WARNING: this snippet may cause an infinite loop
const cursor = myColl.find();
while (cursor.hasNext()) {
console.log(cursor.next());
}
}

由于 hasNext() 的调用返回一个 Promise,条件语句无论解析的值是什么都返回 true

如果我们修改代码,只对 next() 的调用使用 await,如以下代码片段所示,它将抛出以下错误: MongoError: Cursor is closed

async function run() {
...
// WARNING: this snippet throws a MongoError
const cursor = myColl.find();
while (cursor.hasNext()) {
console.log(await cursor.next());
}
}

尽管 hasNext()next() 返回结果后才被调用,但 hasNext() 的调用返回一个解析为 true 的 Promise,而不是它解析的值,类似于前面的示例。代码尝试在已经返回其结果并因此关闭的游标上调用 next()

如果我们修改代码,只对 hasNext() 的调用使用 await,如以下示例所示,控制台将打印 Promise 对象而不是文档对象。

async function run() {
...
// WARNING: this snippet prints Promises instead of the objects they resolve to
const cursor = myColl.find();
while (await cursor.hasNext()) {
console.log(cursor.next());
}
}

在使用 hasNext()next() 方法调用之前使用 await,以确保您操作的是正确的返回值,如以下代码所示

async function run() {
...
const cursor = myColl.find();
while (await cursor.hasNext()) {
console.log(await cursor.next());
}
}

返回

副本集操作