如何判断对象是否为Promise?

时间:2015-01-02 17:47:49

标签: javascript promise q bluebird es6-promise

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

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

17 个答案:

答案 0 :(得分:267)

承诺库如何决定

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

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

如果我们查看specification

  

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

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

  

then ables的这种处理允许promise实现进行互操作,只要它们公开Promise / A +兼容的then方法。它还允许Promises / A +实现用合理的方法“同化”不一致的实现。

你应该如何决定

你不应该 - 而是在始终将任何值或外部Promise.resolve(x)转换为信任的Q(x)then。诺言。它比自己执行这些检查更安全,更容易。

真的需要确定吗?

您始终可以通过the test suite:D

运行它

答案 1 :(得分:130)

检查某些内容是否有必要使代码变得复杂,只需使用Promise.resolve

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

})

答案 2 :(得分:74)

这是我的原始答案,此后ratified in the spec作为测试承诺的方式:

Promise.resolve(obj) == obj

这是有效的,因为algorithm明确要求Promise.resolve必须返回传入的确切对象if和 仅当 它是一个承诺时规范的定义。

我在这里有另一个答案,过去曾经说过这个,但当时它与Safari无法合作时,我将其更改为其他内容。那是一年前的事,即使在Safari中也能正常运行。

我会编辑我的原始答案,除非感觉不对,因为现在有更多人投票支持该答案中的改变解决方案而不是原始答案。我相信这是更好的答案,我希望你同意。

答案 3 :(得分:45)

更新:这不再是最佳答案。请改为投票my other answer

obj instanceof Promise

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

如果您正在使用垫片,承诺库或任何其他假装类似承诺的东西,那么测试“thenable”(任何带有.then方法的东西)可能更合适,如在这里的其他答案中显示。

答案 4 :(得分:40)

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

答案 5 :(得分:13)

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

function isPromise(p) {
  return p && Object.prototype.toString.call(p) === "[object Promise]";
}
直接来自toString的{​​p> Call Object.prototype返回给定对象类型的native string representation,在我们的案例中为"[object Promise]"。这确保了给定的对象

  • 绕过误报,如...:
    • 具有相同构造函数名称的自定义对象类型(" Promise")。
    • 给定对象的自编toString方法。
  • 适用于多种环境情境(例如iframe)in contrast to instanceofisPrototypeOf

但是,任何具有host object的特定tag modified via Symbol.toStringTag都可以返回"[object Promise]"。这可能是预期的结果,取决于项目(例如,如果有自定义的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 
}

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

  

" function Identifier FormalParameterList opt ){ FunctionBody }"

以上相应处理。 FunctionBody 在所有主流浏览器中均为[native code]

MDN: Function.prototype.toString

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

答案 6 :(得分:6)

以下是代码格式https://github.com/ssnau/xkit/blob/master/util/is-promise.js

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

如果对象采用then方法,则应将其视为Promise

答案 7 :(得分:6)

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

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

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

如果该函数今天没有返回承诺,但是明天返回了一个承诺或被声明为异步,那么您将可以保证未来发展。

答案 8 :(得分:5)

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

答案 9 :(得分:5)

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

答案 10 :(得分: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));
});

答案 11 :(得分:2)

这是graphql-js程序包检测承诺的方式:

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

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

答案 12 :(得分:2)

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

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

答案 13 :(得分:0)

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

我没有检查过任何非本地图书馆,但现在有什么意义?

答案 14 :(得分:0)

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

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

答案 15 :(得分:-1)

在搜索可靠方式检测异步功能甚至承诺后,我最终使用了以下测试:

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

答案 16 :(得分:-3)

ES6:

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

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