无论是ES6承诺还是蓝鸟承诺,Q承诺等等。

我如何测试,看看一个给定的对象是一个承诺?


当前回答

要查看给定对象是否为ES6 Promise,可以使用以下谓词:

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

直接从对象调用toString。prototype返回给定对象类型的原生字符串表示,在本例中为“[object Promise]”。这确保了给定的对象

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

然而,任何特定的宿主对象,其标记通过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 
}

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

函数标识符(FormalParameterListopt) {FunctionBody}"

这是上面相应的处理。在所有主流浏览器中,FunctionBody都是[本机代码]。

MDN: Function.prototype.toString

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

其他回答

承诺库如何决定

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

Promises/A+规范有一个叫做thenable的概念,它基本上是“带有then方法的对象”。承诺会而且应该用一种正确的方法来吸收任何东西。所有你提到的承诺实现都是这样做的。

如果我们看一下说明书:

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

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

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

你应该如何决定

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

真的需要确定吗?

您总是可以在测试套件中运行它:D

如果你正在使用Typescript,我想补充一点,你可以使用“类型谓词”功能。只应该将逻辑验证包装在返回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
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));
});
if (typeof thing?.then === 'function') {
    // probably a promise
} else {
    // definitely not a promise
}