Docs 菜单
Docs 主页
/ / /
Node.js 驱动程序
/

Promises

在此页面上

  • Overview
  • Promises
  • Await 操作符
  • 操作注意事项

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

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

本部分介绍了 Promises,您可以将其与 Node.js 驱动程序一起使用,以访问针对 MongoDB 集群的方法调用的结果。

Promise 是异步方法调用返回的对象,它允许您访问有关它们封装的操作最终成功或失败的信息。如果操作仍在运行,则 Promise 处于待定状态;如果操作成功完成,则 Promise 处于已履行状态;如果操作引发异常,则 Promise 处于已拒绝状态。有关 Promise 和相关术语的更多信息,请参阅有关 Promise 的 MDN 文档。

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

您可以定义自己的逻辑,通过附加 then() 方法,一旦 Promise 达到 FulfilledRejected 状态,该逻辑就会执行。then() 的第一个参数是 Promise 达到 Fulfilled 状态时调用的方法,可选的第二个参数是 Promise 达到 Rejected 状态时调用的方法。then() 方法会返回一个 Promise,您可以在其中附加更多 then() 方法。

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

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

要仅处理到“拒绝”状态的 Promise 转换,请使用 catch() 方法,而不是将第一个参数 null 传递给 then()catch() 方法接受单个回调,该回调会在 Promise 过渡到 “拒绝”状态时执行。

catch()方法通常追加在 Promise 链接的末尾,以处理抛出的任何异常。以下代码段演示了将catch()方法追加到 Promise 链接的末尾。

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 达到 FulfilledRejected 状态并返回。由于 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}`);
}
}

如需了解更多信息,请参阅有关 await 的 MDN 文档。

使用 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

如果我们将代码更改为 await,仅调用next()(如以下代码段所示),则会引发以下错误: 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());
}
}

虽然在 next() 结果返回之后才会调用 hasNext(),但对 hasNext() 的调用会返回一个 Promise,而其计算结果为 true 而不是解析出的值(与前一示例类似)。此代码会尝试对已返回其结果并因此而关闭的 Cursor 调用 next()

如果我们将代码更改为仅 awaithasNext()调用(如下例所示),控制台将打印 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());
}
}

后退

对副本集的操作