444

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

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

4

19 回答 19

439

Promise 库如何决定

如果它有一个.then功能 - 这是唯一的标准承诺库使用。

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

如果我们看一下规范

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

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

这种对thenables 的处理允许promise 实现互操作,只要它们公开一个符合Promises/A+ 的then方法。它还允许 Promises/A+ 实现使用合理的 then 方法“吸收”不符合要求的实现。

你应该如何决定

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

真的需要确定吗?

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

于 2015-01-02T17:49:25.103 回答
259

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

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

})
于 2015-01-03T23:02:28.270 回答
119

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

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

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

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

于 2016-07-12T21:29:42.037 回答
90

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

obj instanceof Promise

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

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

于 2015-01-25T04:09:49.283 回答
60
if (typeof thing?.then === 'function') {
    // probably a promise
} else {
    // definitely not a promise
}
于 2015-01-02T17:53:31.943 回答
30

要查看给定对象是否是ES6 Promise,我们可以使用这个谓词:

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

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

  • 绕过误报,例如..:
    • 具有相同构造函数名称的自定义对象类型(“Promise”)。
    • 给定对象的自写toString方法。
  • 与or相比,可以instanceof跨多个环境上下文(例如 iframe)工作isPrototypeOf

但是,任何通过 修改其标签的特定主机对象都可以返回。这可能是预期的结果,也可能不是取决于项目(例如,如果有自定义的 Promise 实现)。Symbol.toStringTag"[object 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 
}

根据规范的thisthis section,函数的字符串表示应该是:

“函数标识符FormalParameterList opt){ FunctionBody }”

上面相应地处理。FunctionBody存在[native code]于所有主流浏览器中。

医疗器械网络:Function.prototype.toString

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

于 2017-08-18T18:14:41.927 回答
20

这就是graphql-js包检测 Promise 的方式:

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

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

于 2018-12-28T08:33:34.263 回答
14

不是完整问题的答案,但我认为值得一提的是,在 Node.js 10isPromise中添加了一个名为的新 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
于 2018-05-04T21:20:24.700 回答
9

如果您使用异步方法,则可以这样做并避免任何歧义。

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

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

如果该函数今天没有返回一个承诺,但明天返回一个或被声明为异步,那么您将是面向未来的。

于 2018-07-27T17:23:09.297 回答
7

这是代码形式https://github.com/ssnau/xkit/blob/master/util/is-promise.js

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

如果一个对象有一个then方法,它应该被视为一个Promise.

于 2016-07-01T16:09:00.020 回答
6

如果您使用的是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

于 2018-02-14T19:24:44.460 回答
3

在寻找一种可靠的方法来检测异步函数甚至Promises之后,我最终使用了以下测试:

() => fn.constructor.name === 'Promise' || fn.constructor.name === 'AsyncFunction'
于 2018-05-30T14:48:36.817 回答
3

任何为了避免比较而推动可能同步的东西都会将您的代码变成原本可以避免的异步valuePromise.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

我还没有根据任何非本地图书馆检查它,但现在有什么意义呢?

于 2021-03-01T17:27:48.710 回答
2
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));
});
于 2017-06-29T22:38:44.767 回答
2

我将此功能用作通用解决方案:

function isPromise(value) {
  return value && value.then && typeof value.then === 'function';
}
于 2020-05-18T11:55:53.883 回答
0

在角:

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

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

Ĵ

于 2021-10-06T23:29:43.830 回答
0

使用这个库

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
于 2021-11-22T03:18:24.937 回答
0
const isPromise = (value) => {
  return !!(
    value &&
    value.then &&
    typeof value.then === 'function' &&
    value?.constructor?.name === 'Promise'
  )
}

至于我 - 这个检查更好,试试看

于 2021-01-16T10:41:29.117 回答
-3

ES6:

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

console.log(promise.toString().includes('Promise')); //true
于 2017-12-22T00:27:42.030 回答