如何检查一个对象是否为Promise?

无论是ES6 Promise还是蓝鸟Promise, Q Promise等。

如何测试给定对象是否为Promise?

228429 次浏览

承诺库如何决定

如果它有.then函数-这是只有标准承诺库使用。

Promises/A+规范有一个名为thenable的概念,它基本上是“具有then方法的对象”。Promises将并且应该用then方法同化任何东西。所有你提到的承诺实现都是这样做的。

如果我们看规范:

2.3.3.3如果then是一个函数,用x调用它,第一个参数resolvePromise,第二个参数rejectPromise

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

thenables的这种处理方式允许promise实现互操作,只要它们公开一个符合Promises/ a +的then方法。它还允许Promises/A+实现用合理的then方法“同化”不符合规范的实现。

你应该如何决定

你不应该——而是调用Promise.resolve(x) (Q中的Q(x)),它将总是将任何值或外部thenable转换为可信承诺。这比自己进行这些检查更安全、更容易。

真的需要确定吗?

你总是可以通过测试套件:D来运行它

if (typeof thing?.then === 'function') {
// probably a promise
} else {
// definitely not a promise
}

检查一些不必要的承诺会使代码复杂化,只需使用Promise.resolve

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


})

免责声明:对更新OP不是一个很好的答案,只适用于本机,不能跨领域。用accepted answer代替。

obj instanceof Promise

应该这么做。请注意,这可能只与本地es6承诺可靠地工作。

如果你正在使用一个垫片,一个承诺库或任何其他假装承诺样的东西,那么它可能更适合测试一个&;而不是enable&;(任何带有.then方法的东西),如这里的其他答案所示。

下面是代码表单https://github.com/ssnau/xkit/blob/master/util/is-promise.js

!!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function';

如果对象具有then方法,则应将其视为Promise

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

这个答案,基于规范是一种测试承诺的方法,仅供参考。

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

这是因为算法显式要求Promise.resolve必须返回传入if的确切对象,而< >强只有< / >强由这个构造函数创建的Promise

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));
});

要查看给定对象是否为ES6承诺,可以使用这个谓词:

function isPromise(p) {
return p && Object.prototype.toString.call(p) === "[object Promise]";
}

Calling toString直接从Object.prototype返回给定对象类型的本机字符串表示,在本例中为"[object Promise]"。这确保了给定的对象

  • 绕过误报,例如..:
    • 具有相同构造函数名称(“Promise”)的自定义对象类型。
    • 给定对象的自编写toString方法。
    • 李< / ul > < / >
    • 工作在多个环境上下文(例如iframes) instanceof相反isPrototypeOf

    然而,任何特定的宿主对象,只要有它的标签通过Symbol.toStringTag修改,就可以返回"[object Promise]"。这可能是预期的结果,也可能不是,这取决于项目(例如,如果有一个自定义的承诺实现)。


    要查看对象是否来自本机ES6承诺,可以使用:

    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
    }
    

    根据规范的本节,函数的字符串表示形式应该是:

    "函数标识符 (FormalParameterList <子>选择子> < /) {FunctionBody}"

    这是上面相应的处理。FunctionBody在所有主流浏览器中都是[native code]

    MDN: Function.prototype.toString

    这也适用于多个环境上下文。

ES6:

const promise = new Promise(resolve => resolve('olá'));


console.log(promise.toString().includes('Promise')); //true

如果你正在使用打印稿,我想补充一点,你可以使用“类型谓词”特性。只应该将逻辑验证包装在返回x is Promise<any>的函数中,您不需要进行类型转换。在下面的例子中,c要么是一个promise,要么是我想通过调用c.fetch()方法将其转换为promise的类型之一。

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

这并不是完整问题的答案,但我认为值得一提的是,在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

在搜索了可靠的方法来检测异步函数甚至承诺之后,我最终使用了以下测试:

() => fn.constructor.name === 'Promise' || fn.constructor.name === 'AsyncFunction'

如果你在一个异步方法中,你可以这样做,避免任何歧义。

async myMethod(promiseOrNot){
const theValue = await promiseOrNot()
}

如果函数返回promise,它将等待并返回已解析的值。如果函数返回一个值,它将被视为已解析。

如果函数今天没有返回一个承诺,但明天返回一个承诺,或者被声明为异步,那么你将是不受未来影响的。

这是graphql-js包检测承诺的方法:

function isPromise(value) {
return Boolean(value && typeof value.then === 'function');
}

value是函数的返回值。我在我的项目中使用这段代码,到目前为止还没有问题。

我用这个函数作为通用解:

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'
)
}

对我来说,这张支票更好,试试吧

任何为了避免比较而将可能同步的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

我还没有对任何非本地库进行检查,但现在有什么意义呢?

角:

import { isPromise } from '@angular/compiler/src/util';


if (isPromise(variable)) {
// do something
}

J

使用这个库

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