猫鼬承诺文档说查询不是承诺?

Posted

技术标签:

【中文标题】猫鼬承诺文档说查询不是承诺?【英文标题】:Mongoose promises documentation says queries are not promises? 【发布时间】:2019-05-27 00:03:26 【问题描述】:

来自文档(Mongoose v5.4.1,最新版本):

Mongoose 异步操作,如 .save() 和查询,返回 那时的事。 这意味着您可以执行 MyModel.findOne().then() 之类的操作

文档中的第二段说明:

Mongoose 查询不是承诺。他们有一个用于 co 的 .then() 函数 和 async/await 方便。

Javascript MDN 网页说明了什么:

then() 方法返回一个 Promise。

这是否意味着 mongoose 有另一种异步函数的实现,他们为异步操作的结果保留 then 关键字?

换句话说,它们的行为类似于 Promise,但不是 JS Promise?

【问题讨论】:

【参考方案1】:

来自documentation:

Mongoose 查询不是承诺。他们有一个.then() 函数 和 async/await 作为一种方便。然而,与 promises 不同的是,调用 查询的.then()可以多次执行查询。

因此,与实际的承诺不同,如果您在查询中多次调用 then(),您实际上是多次执行查询(或更新)。

如果您想要一个实际的承诺,请在查询中调用exec()

let promise = Test.findOne().exec();

【讨论】:

【参考方案2】:

所有 promises 都是 thenables,但并非所有 thenables 都是 promises。更复杂的是,并非所有 promises 都是 Promises(由 javascript 的内置 Promise 构造函数创建的实例)。

JavaScript 承诺是 Promises/A+ specification 的一个实现,它定义了这样的术语:

1.1 “promise”是具有then 方法的对象或函数,其行为符合本规范。

1.2 “thenable”是定义then方法的对象或函数。

所以 Mongoose 的查询不是承诺,即使按照这个定义也不行,因为他们的 then 方法与 Promises/A+ 规范兼容。请参阅JohnnyHK's answer,了解它们与 Promises/A+ 规范不兼容的原因(它们运行查询)。

换句话说,它们的行为类似于 Promise,但不是 JS Promise?

他们只是有点像承诺。它们不是承诺。他们的then 没有按照规范实现,它有副作用(运行查询)。如果你想要一个真正的承诺,请参阅JohnnyHK's answer(例如,使用exec)。


一般来说,如果你有一个至少有点类似于 Promise 的 thenable,你可以通过使用 Promise.resolve 得到一个适当的 Promise:

Promise.resolve(theThenable)
.then(/*...*/)
.catch(/*...*/)
.finally(/*...*/);

Promise.resolve 将提供一个真正的Promise 实例,解析 Mongoose thenable/promise:它将等待 thenable/promise 解决,然后以相同的方式解决。这适用于 Mongoose 查询(前提是您只执行一次;exec 是 Mongoose 查询的更好方法)。

【讨论】:

我明白了。换句话说,如果我不将其打包在 Promise 中,那么 then() 之后的 catch() 将毫无意义? @eugen 如果是“承诺”,.then() 必须返回“承诺”,您可以将其用作Promise,不会有任何区别。 @eugensunic - 所有 Mongoose 文档都承诺提供 then(如果符合规范,也可用于 catch 情况)。但是,如果您想在对象上实际使用catchfinally,请改为获取真正的Promise(通过Promise.resolve(theThenable)。如果您只需要then 方法,那么您可以直接使用它。 @JonasWilms - 这取决于。如果 Mongoose 的 then 返回一个不是 Promise 的 Mongoose 承诺,并且 Eugen 将其传递给期待真正的 Promise 的东西,这可能是有问题的。所有在 JavaScript 规范中使用 Promise 的方式都只依赖于then,但这并不适用于用户空间代码......【参考方案3】:

它们是“promise like”,这意味着您可以await 他们并在他们身上调用.then().catch(),但他们不是instanceof Promise

【讨论】:

以上是关于猫鼬承诺文档说查询不是承诺?的主要内容,如果未能解决你的问题,请参考以下文章

猫鼬模型保存后返回承诺

猫鼬保存()不返回承诺

在 for 循环中链接猫鼬承诺

猫鼬批量保存承诺

蓝鸟承诺:循环猫鼬结果

链接猫鼬承诺的语法