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

504
无论是 ES6 的 Promise,还是 Bluebird 的 Promise、Q 的 Promise 等等。
我该如何测试一个给定的对象是否为 Promise

4
你最多只能检查一个对象是否有 .then 方法,但这并不能确定你得到的是一个 Promise。此时你所知道的只是该对象具有类似 Promise 的 .then 方法。 - Scott Offen
@ScottOffen 承诺规范_明确地_没有区别。 - Benjamin Gruenbaum
8
我的观点是任何人都可以创建一个暴露了.then方法的对象,但这并不意味着它是Promise,也不会像Promise一样运作,并且可能根本没想过要像Promise一样使用它。检查是否存在.then方法只能告诉你如果对象没有.then方法,则你没有Promise。相反,存在.then方法并不一定意味着你Promise。 - Scott Offen
5
按照定义,确认一个Promise对象的唯一方法是检查它是否有.then方法。是的,这种方法可能会出现误判,但所有的Promise库都依赖于这种假设(因为它们只能依赖于这个)。我所能想到的唯一替代方案是采用Benjamin Gruenbaum提出的建议并将其运行通过Promise测试套件。但对于实际的生产代码来说,这不太实际。 - JLRishe
3
const isPromise = v => typeof v === 'object' && typeof v.then === 'function' 可以翻译为“判断变量是否为 Promise 的函数,判断依据是变量的类型为对象并且具有 then 方法”。 - Dominic
显示剩余3条评论
20个回答

6

如果您正在使用Typescript,我想补充一下,您可以使用“类型谓词”功能。只需将逻辑验证包装在返回x是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

(此处为原文,未做翻译)

5

任何将可能同步的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

我还没有与任何非原生库进行比对,不过现在这有什么意义呢?


4

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

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

如果你子类化Promise并创建它的实例,这个测试可能会失败。不过这应该适用于你大部分想要测试的内容。 - theram
同意,但我不明白为什么有人要创建Promise的子类。 - Sebastien H.
fn.constructor.name === 'AsyncFunction' 是错误的 - 它意味着某些东西是异步函数而不是 Promise - 而且它也不能保证有效,因为人们可以子类化 Promises。 - Benjamin Gruenbaum
@BenjaminGruenbaum 上述示例在大多数情况下都有效,如果您创建自己的子类,则应将测试添加到其名称上。 - Sebastien H.
你可以这样做,但如果你已经知道有哪些对象,那么你就已经知道这些东西是否是 promises。 - Benjamin Gruenbaum
显示剩余2条评论

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

2
我使用这个函数作为通用解决方案:
function isPromise(value) {
  return value && value.then && typeof value.then === 'function';
}

0
const isPromise = (value) => {
  return !!(
    value &&
    value.then &&
    typeof value.then === 'function' &&
    value?.constructor?.name === 'Promise'
  )
}

对我来说 - 这个检查更好,试一下吧


0

对于那些试图在TypeScript中实现此操作的人 - 其他提供的解决方案会出错:

if (p instanceof Object && 'then' in p && typeof p.then === 'function') { ... }

这在JavaScript中似乎也有效 - 为什么特别提到TypeScript? - undefined
1
其他解决方案都有效,只是TypeScript编译器对它们提出了一些抱怨,所以我提供了一个TypeScript编译器认可的解决方案,以节省下一个人的时间。 - undefined
1
非常感谢。我遇到了一个情况,其中一个 JavaScript 变量可能是一个基于 Promise 的对象,也可能不是。 - undefined

-1

在Angular中:

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

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

J


-2
请使用这个库。

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

-3

ES6:

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

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

2
任何拥有(或已重写)toString方法的对象都可以返回一个包含“Promise”的字符串。 - Boghyon Hoffmann
6
这个回答有很多问题,其中最明显的是'NotAPromise'.toString().includes('Promise') === true - damd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接