我如何判断一个对象是否是一个 Promise?

IT技术 javascript promise q bluebird es6-promise
2021-01-25 08:13:49

无论是 ES6 Promise 还是 bluebird Promise、Q Promise 等。

我如何测试一个给定的对象是否是一个 Promise?

6个回答

Promise库如何决定

如果它有一个.then函数——那是唯一使用的标准Promise库。

Promises/A+ 规范有一个叫做then能够的概念,它基本上是“一个带有then方法的对象”。Promise 将并且应该使用 then 方法吸收任何东西你提到的所有Promise实现都是这样做的。

如果我们看一下规范

2.3.3.3 ifthen是一个函数,用 x 作为 this 调用它,第一个参数是 resolvePromise,第二个参数是 rejectPromise

它还解释了此设计决策的基本原理:

这种对能力的处理then允许 promise 实现互操作,只要它们公开一个 Promises/A+ 兼容的then方法。它还允许 Promises/A+ 实现用合理的 then 方法“同化”不一致的实现。

你应该如何决定

你不应该 - 而是调用Promise.resolve(x)Q(x)在 Q 中),它总是将任何值或外部then能力转换为受信任的Promise。这比自己执行这些检查更安全、更容易。

真的需要确定吗?

您始终可以通过测试套件运行它:D

@Ben 不是,您几乎从不想关心某事是否是Promise -Promise.resolve自动为您处理这件事 - 您总是会得到Promise。
2021-03-19 08:13:49
执行 Promise.resolve(x) (Q(x) in Q) 如何告诉你 x 是否是一个Promise?
2021-03-24 08:13:49

检查是否有一些Promise会不必要地使代码复杂化,只需使用 Promise.resolve

Promise.resolve(valueOrPromiseItDoesntMatter).then(function(value) {

})
@AlexMills 是的,它甚至适用于像 jQuery Promise这样的非标准Promise。如果对象的 then 方法与 promise then 的接口完全不同,则它可能会失败。
2021-03-17 08:13:49
这个答案虽然可能是很好的建议,但实际上并没有回答这个问题。
2021-03-17 08:13:49
@Esalija 我有一个变量来指示代码是否已加载。这个变量可以是一个表示它正在加载的Promise,我应该等待它或者一个表示它已加载的值,以便我可以正确地呈现它。值得一提的是,我将渲染一个加载动画,如果它仍在加载,则非常复杂。因此,无论如何我都不能等待,因为如果我总是等待,render() 将使用未每次加载的代码调用并创建整个加载动画,即使它已经准备就绪。
2021-03-17 08:13:49
@Esalija 这个问题在我看来是相关且重要的,而不仅仅是对 Promise 库的实现者。它也与Promise 库用户有关,他们想知道实现将/应该/可能如何表现以及不同的 Promise 库将如何相互交互。尤其是,这个用户对我可以为任何 X 做出 X Promise的明显事实感到非常沮丧,除非 X 是“Promise”(无论“Promise”在这里意味着什么——这就是问题),我绝对感兴趣确切地知道该异常的边界在哪里。
2021-03-28 08:13:49
除非问题真的是关于某人实际实现了一个Promise库,否则这个问题是无效的。只有一个Promise库需要做检查,之后你可以像我展示的那样使用它的 .resolve 方法。
2021-04-05 08:13:49

免责声明:不是更新 OP 的好答案,是每个库的,并且不能跨领域工作。.then改为检查

这个基于规范的答案是一种测试仅有时有效的Promise的方法,仅供参考。

Promise.resolve(obj) == obj &&
BLUEBIRD.resolve(obj) == obj

当这有效时,这是因为算法明确要求Promise.resolve必须返回传入的确切对象,当且仅当它是由此构造函数创建Promise

如果此答案首先说明您如何解释问题而不是立即从答案开始,则可以改进该答案-不幸的是,OP 根本没有说清楚,而您也没有说清楚,所以在这一点上OP、作者和读者可能在 3 个不同的页面上。您引用的文档说“如果参数是此构造函数产生的Promise”,斜体部分至关重要。最好说明这就是您要回答的问题。此外,您的答案对这个库的用户有用,但对实现者没有用。
2021-03-13 08:13:49
不要使用这种方法,这就是原因,更多的是@BenjaminGruenbaum 的观点。gist.github.com/reggi/a1da4d0ea4f1320fa15405fb86358cff
2021-03-29 08:13:49
“规范定义的Promise”似乎意味着“由与通过 Promise.resolve() 创建的Promise相同的构造函数创建的Promise将是”——因此这将无法检测,例如。一个 polyfill 的 Promise 实际上是一个 Promise
2021-04-01 08:13:49
对于不属于同一领域的Promise,这也将失败。
2021-04-04 08:13:49
你应该使用===而不是==吗?
2021-04-05 08:13:49

免责声明:不是更新 OP 的好答案,仅适用于本机,不适用于跨领域。改为遵循接受的答案

obj instanceof Promise

应该这样做。请注意,这可能仅适用于原生 es6 Promise。

如果您使用的是 shim、promise 库或任何其他伪装成类似 promise 的东西,那么测试“thenable”(任何带有.then方法的东西可能更合适,如此处的其他答案所示。

对于不同领域的Promise,这将失败。
2021-03-13 08:13:49
是的,这个答案实际上是错误的。我最终在这里解决了一个如此难以跟踪的问题。你真的应该检查一下obj && typeof obj.then == 'function',因为它适用于所有类型的Promise,实际上是规范推荐的方式,并被实现/polyfills使用。本土Promise.all例如将所有工作thenABLES,不仅其他本地的Promise。你的代码也应该如此。所以instanceof Promise不是一个好的解决方案。
2021-03-21 08:13:49
此后有人向我指出Promise.resolve(obj) == obj在 Safari无法使用。使用instanceof Promise来代替。
2021-03-29 08:13:49
这不能可靠地工作,并导致我疯狂地难以跟踪问题。假设您有一个使用 es6.promise shim 的库,并且您在某处使用 Bluebird,您会遇到问题。这个问题在 Chrome Canary 中出现。
2021-04-01 08:13:49
跟帖-这更糟糕的是:在仅使用原生的Promise,现在我正在调试那些有问题的Node.js 6.2.2 console.log(typeof p, p, p instanceof Promise);,输出结果:object Promise { <pending> } false正如您所看到的,这是一个Promise - 但instanceof Promise测试返回了false吗?
2021-04-04 08:13:49
if (typeof thing?.then === 'function') {
    // probably a promise
} else {
    // definitely not a promise
}
如果事物未定义怎么办?你需要通过东西&&来防止这种情况......
2021-03-15 08:13:49
@mrBorna ?inthing?.then处理未定义的检查。这称为“可选链接”。阅读更多:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
2021-04-02 08:13:49
不是最好的,但绝对是很有可能的;还取决于问题的范围。100% 防御性编写通常适用于开放式公共 API,或者您知道数据的形状/签名是完全开放式的。
2021-04-04 08:13:49
if (p && 'then' in p && typeof p.then === 'function')
2021-04-04 08:13:49