如何检查对象是否为承诺
How to check if an object is a Promise?
无论是ES6 Promise
还是蓝鸟Promise
,Q Promise
等。
如何测试给定对象是否为Promise
?
承诺库如何决定
如果它有一个.then
函数 - 这是库使用的唯一标准承诺。
Promises/A+ 规范有一个叫做 then
able 的概念,它基本上是"具有then
方法的对象"。承诺将而且应该用当时的方法吸收任何东西。你提到的所有承诺实现都是这样做的。
如果我们看一下规范:
2.3.3.3 如果
then
是一个函数,则用x调用它,第一个参数resolvePromise,第二个参数rejectPromise
它还解释了此设计决策的基本原理:
这种对
then
能力的处理允许承诺实现进行互操作,只要它们公开符合 Promises/A+ 的then
方法。它还允许 Promises/A+ 实现使用合理的 then 方法"吸收"不符合要求的实现。
你应该如何决定
你不应该 - 而是调用Promise.resolve(x)
(Q(x)
在Q中),它将始终将任何值或外部then
转换为可信的承诺。这比自己执行这些检查更安全、更容易。
真的需要确定吗?
您始终可以通过测试套件运行它:D
检查某些内容是否不必要地使代码复杂化,只需使用Promise.resolve
Promise.resolve(valueOrPromiseItDoesntMatter).then(function(value) {
})
免责声明:更新的OP不是一个好的答案,是每个库的,并且不能跨领域工作。请改为检查.then
。
仅供参考,基于规范的这个答案是一种测试仅在有时有效的承诺的方法。
Promise.resolve(obj) == obj &&
BLUEBIRD.resolve(obj) == obj
当这起作用时,这是因为算法明确要求Promise.resolve
必须返回传入的确切对象,当且仅当它是此构造函数创建的承诺时。
免责声明:不是更新 OP 的好答案,仅适用于本机,不适用于跨领域。请改为遵循接受的答案。
obj instanceof Promise
应该这样做。请注意,这可能仅适用于本机 es6 承诺。
如果您使用的是垫片、promise 库或其他任何假装类似 promise 的东西,那么测试"thenable"(任何具有.then
方法的方法)可能更合适,如此处其他答案所示。
if (typeof thing?.then === 'function') {
// probably a promise
} else {
// definitely not a promise
}
要查看给定的对象是否是 ES6 Promise,我们可以利用这个谓词:
function isPromise(p) {
return p && Object.prototype.toString.call(p) === "[object Promise]";
}
直接从Object.prototype
Call
toString
返回给定对象类型的本机字符串表示形式,在我们的例子中"[object Promise]"
。这可确保给定的对象
- 绕过误报,例如:
- 具有相同构造函数名称("Promise")的自定义对象类型。
- 给定对象的自写
toString
方法。
- 与
instanceof
或isPrototypeOf
相比,跨多个环境上下文(例如 iframe)工作。
但是,任何通过 Symbol.toStringTag
修改其标记的特定主机对象都可以返回 "[object Promise]"
。这可能是预期的结果,也可能不是,具体取决于项目(例如,是否有自定义的 Promise 实现)。
要查看对象是否来自原生 ES6 Promise,我们可以使用:
function isNativePromise(p) {
return p && typeof p.constructor === "function"
&& Function.prototype.toString.call(p.constructor).replace(/'(.*')/, "()")
=== Function.prototype.toString.call(/*native object*/Function)
.replace("Function", "Promise") // replacing Identifier
.replace(/'(.*')/, "()"); // removing possible FormalParameterList
}
根据规范的这一部分和这一部分,函数的字符串表示应该是:
"function Identifier ( FormalParameterListopt ) { FunctionBody }"
上面对此进行了相应的处理。FunctionBody 在所有主流浏览器中都[native code]
。
MDN: Function.prototype.toString
这也适用于多个环境上下文。
这就是 graphql-js 包检测承诺的方式:
function isPromise(value) {
return Boolean(value && typeof value.then === 'function');
}
value
是函数的返回值。我在我的项目中使用此代码,到目前为止没有问题。
不是完整问题的答案,但我认为值得一提的是,在 Node.js 10 中添加了一个名为 isPromise
的新 util 函数,用于检查对象是否是本机 Promise:
const utilTypes = require('util').types
const b_Promise = require('bluebird')
utilTypes.isPromise(Promise.resolve(5)) // true
utilTypes.isPromise(b_Promise.resolve(5)) // false
如果您使用的是异步方法,则可以执行此操作并避免任何歧义。
async myMethod(promiseOrNot){
const theValue = await promiseOrNot()
}
如果函数返回 promise,它将等待并返回解析的值。 如果函数返回一个值,它将被视为已解析。
如果函数今天没有返回承诺,但明天返回一个或被声明为异步,那么您将是面向未来的。
这是代码形式 https://github.com/ssnau/xkit/blob/master/util/is-promise.js
!!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function';
如果对象具有then
方法,则应将其视为Promise
。
如果您使用的是 Typescript,我想补充一点,您可以使用"类型谓词"功能。只需将逻辑验证包装在返回x is Promise<any>
的函数中,就不需要进行类型转换。在我的示例中,c
要么是一个承诺,要么是我想通过调用 c.fetch()
方法转换为承诺的类型之一。
export function toPromise(c: Container<any> | Promise<any>): Promise<any> {
if (c == null) return Promise.resolve();
return isContainer(c) ? c.fetch() : c;
}
export function isContainer(val: Container<any> | Promise<any>): val is Container<any> {
return val && (<Container<any>>val).fetch !== undefined;
}
export function isPromise(val: Container<any> | Promise<any>): val is Promise<any> {
return val && (<Promise<any>>val).then !== undefined;
}
更多信息: https://www.typescriptlang.org/docs/handbook/advanced-types.html
在寻找一种可靠的方法来检测异步函数甚至 Promise 之后,我最终使用了以下测试:
() => fn.constructor.name === 'Promise' || fn.constructor.name === 'AsyncFunction'
任何将可能的同步value
推送到Promise.resolve(value)
以避免比较的舒适性都会将您的代码变成原本可以避免的异步。有时你不想在那个阶段。你想知道在微任务队列中的一些早期解决方案咬你之前评估的结果对吗..?
人们可能会喜欢;
var isPromise = x => Object(x).constructor === Promise;
我根据我能想到的一些边缘情况检查了它,它似乎有效。
isPromise(undefined); // <- false
isPromise(null); // <- false
isPromise(0); // <- false
isPromise(""); // <- false
isPromise({}); // <- false
isPromise(setTimeout); // <- false
isPromise(Promise); // <- false
isPromise(new Promise((v,x) => setTimeout(v,1000,"whatever"))); // <- true
isPromise(fetch('http://example.com/movies.json')); // <- true
我还没有检查过任何非本地图书馆,但现在有什么意义?
it('should return a promise', function() {
var result = testedFunctionThatReturnsPromise();
expect(result).toBeDefined();
// 3 slightly different ways of verifying a promise
expect(typeof result.then).toBe('function');
expect(result instanceof Promise).toBe(true);
expect(result).toBe(Promise.resolve(result));
});
我使用此函数作为通用解决方案:
function isPromise(value) {
return value && value.then && typeof value.then === 'function';
}
const isPromise = (value) => {
return !!(
value &&
value.then &&
typeof value.then === 'function' &&
value?.constructor?.name === 'Promise'
)
}
至于我 - 这个检查更好,试试看
对于那些尝试在 Typescript 中执行此操作的人 - 其他提供的解决方案存在哪些错误:
if (p instanceof Object && 'then' in p && typeof p.then === 'function') { ... }
使用此库
https://www.npmjs.com/package/is-promise
import isPromise from 'is-promise';
isPromise(Promise.resolve());//=>true
isPromise({then:function () {...}});//=>true
isPromise(null);//=>false
isPromise({});//=>false
isPromise({then: true})//=>false
ES6:
const promise = new Promise(resolve => resolve('olá'));
console.log(promise.toString().includes('Promise')); //true
- 如何检查数组中的对象是否等于选项值
- 测试对象是否相等和/或对象是否有更多的关键点,但仍然与共同的关键点相等
- 确定javascript中的html表对象是否具有<colgroup>是否
- 验证对象是否为null Javascript/Angularjs
- 如何通过json对象选项卡中的Id来检查对象是否存在
- jQuery-检测选择对象是否添加或删除了选项
- 检查对象是否是mongo游标
- Three.js-如何检查对象是否在球体后面(不可见)
- 检查对象是否基于jquery对象
- 在JSON项上循环,无论JSON对象是否具有多个数组
- 递归Javascript对象是否会导致任何问题(内存泄漏)
- Javascript如何确定两个对象是否相同
- 如何检查文字对象是否在 Javascript 数组中
- 检查对象是否已被推入数组 Js
- 变量/对象是否按值传递,为什么我不能在 javascript 中使用变量更改对象的属性
- JavaScript 如何检查包含数组的对象是否为空
- 嵌套对象是否被视为良好做法
- 在node.js/ssocket.io中,如何判断对象是否是套接字的实例
- 是否有跨浏览器和跨框架的方法来检查对象是否是HTML元素
- 有没有办法检查一个对象是否存在并且在一行中有一个子对象