如何判断对象是否为Promise?

the*_*ram 294 javascript promise q bluebird es6-promise

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

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

Ben*_*aum 305

承诺库如何决定

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

Promises/A +规范有一个名为thenable 的概念,它基本上是"带有then方法的对象".承诺将并且应该用当时的方法吸收任何东西.你提到的所有承诺实现都是这样做的.

如果我们看一下规范:

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

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

这种对thenables的处理允许promise实现进行互操作,只要它们公开Promise/A +兼容then方法即可.它还允许Promises/A +实现使用合理的方法"同化"不一致的实现.

你应该如何决定

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

真的需要确定吗?

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

  • 很好的答案.但有一句话:"你不应该 - 而是调用Promise.resolve(x)"并不总是一个选择.如果你真的想*测试*对象'是'是'承诺'是*那么*能够),`Promise.resolve`将不会告诉你任何东西,并将在过程中转换对象.所以实际上答案是(给定一个名为`subject`的对象):`var isPromise = typeof subject.then =='function';` (85认同)
  • @Oleander这就是它在ECMAScript规范和Promises/A +规范中的定义.如果它有一个`then`方法,那么它将被视为一个承诺,应该通过`Promise.prototype.then`,`Promise.resolve``all``cree`或promise的`fulfill`参数递归地同化.构造函数.因此,您可以在技术上进行不同的检查,但语言本身会经常检查,并且会像这样检查.我不确定你的downvote意味着什么或者它是什么不正确,因为你评论的部分以"如何承诺库决定"开头,这是对的 (16认同)
  • 该线程令人沮丧。JavaScript是一种鸭子式语言。在这方面,承诺不是奇怪的事情。这是一个很好的答案。 (11认同)
  • -1.所有Promise都有一个`then`方法,但所有`then`方法都不属于`Promise`.因此,您的陈述无效,因此无法回答问题. (9认同)
  • @Sebastian尝试等待,您会对发生的事情感到惊讶。 (4认同)
  • @Sebastian根据语言-虽然这是一个承诺-看看当您等待它时会发生什么!JS是行为类型 (4认同)
  • 执行 Promise.resolve(x) (Q 中的 Q(x))如何告知您 x 是否是一个 Promise? (4认同)
  • @BenjaminGruenbaum在我的第一条评论中,我可能听起来有点苛刻,抱歉.我只想保持简短和正式.第二个声明指出; `我如何测试一个给定的对象是否是一个Promise?那是; 鉴于任何一个对象,如果它是一个"承诺",它是如何阻止的.检查`then`的存在将告诉你该对象是一个`Promise`或一个带有`then`方法的`Object`,因此没有回答给定的问题.它增加了对象是"Promise"的可能性,但就是这样. (3认同)
  • @Ben,事实并非如此,你几乎从来不想关心某件事是否是一个承诺 - `Promise.resolve` 会自动为你处理这个问题 - 你总是会得到一个承诺。 (3认同)
  • @DonHatch A +规范将"承诺"称为"当前实现的某些东西",将"可以"称为"应该被视为承诺的东西".仔细读. (2认同)
  • 此外,在“async”上下文中,“await thing”使其解析为“thing”的值或其“承诺”值。 (2认同)

Esa*_*ija 155

检查某些东西是否有必要使代码变得复杂,只需使用即可 Promise.resolve

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

})
Run Code Online (Sandbox Code Playgroud)

  • 这个答案,虽然可能是好的建议,但实际上并没有回答这个问题. (13认同)
  • @Esalija在我看来,问题是相关且重要的,而不仅仅是对承诺库的实施者.它还与promise库的*user*相关,它希望了解实现将如何/应该/可能的行为以及不同的promise库如何相互交互.特别是,这个用户非常沮丧的事实是我可以为任何X做出X的承诺,除非X是"承诺"(无论"承诺"在这里意味着什么 - 这就是问题),我当然感兴趣确切地知道该异常的边界在哪里. (4认同)
  • @AlexMills是的,它甚至适用于非标准的承诺,如jQuery承诺.如果对象的then方法与promise的接口完全不同,则可能会失败. (3认同)
  • 除非问题确实是关于实际实现promise库的人,否则问题无效.只有一个promise库需要进行检查,之后你可以像我展示的一样使用它的.resolve方法. (3认同)
  • @Esailija 我有一个变量来指示代码是否已加载。这个变量可以是一个表示它正在加载的承诺,我应该等待它或者一个表示它已加载的值,以便我可以正确地呈现它。值得一提的是,我将渲染一个加载动画,如果它仍在加载,则非常复杂。因此,无论如何我都不能等待,因为如果我总是等待,render() 将使用未每次加载的代码调用并创建整个加载动画,即使它已经准备就绪。 (2认同)
  • 虽然这不是问题的直接答案,但我最喜欢它。因为我真正的任务是检测 Promise 的存在,然后使用结果。由于我使用的是 TypeScript,我应该为此编写一个类型保护程序。但仅仅 `await res;` 实际上在 JS 和 TS 中都可以完成工作。瞧。 (2认同)

jib*_*jib 87

这是我原来的答案,后来在规范中批准为测试承诺的方式:

Promise.resolve(obj) == obj
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为算法明确要求Promise.resolve必须返回传入的确切对象,当且仅当它是规范定义的承诺时.

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

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

  • 对于不同领域的承诺,这也将失败. (12认同)
  • 你应该使用`===`而不是`==`? (8认同)
  • "规范定义的承诺"似乎意味着"由与Promise.resolve()创建的承诺相同的构造函数创建的承诺将是" - 所以这将无法检测是否例如.polyfilled Promise实际上是一种承诺 (3认同)
  • 这个答案可以通过陈述你如何解释问题而不是立即开始回答来开始改进 - 遗憾的是OP完全没有明确表达,你也没有,所以在这一点上OP,作者和读者可能在3个不同的页面上.您引用的文档说"如果参数是由此构造函数*生成的承诺*",则斜体部分至关重要.最好的说明那就是你要回答的问题.此外,您的答案对此库的用户有用,但对实现者不熟悉. (2认同)

jib*_*jib 51

更新:这不再是最好的答案.请改为投票给我的其他答案.

obj instanceof Promise
Run Code Online (Sandbox Code Playgroud)

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

如果您正在使用垫片,承诺库或任何其他假装类似承诺的东西,那么测试"可以"(使用.then方法的任何东西)可能更合适,如此处的其他答案所示.

  • 这不能可靠地工作,并使我难以追踪问题.假设您有一个使用es6.promise垫片的库,并且您在某处使用Bluebird,则会遇到问题.我在Chrome Canary中遇到了这个问题. (2认同)
  • 是的,这个答案实际上是错误的。我最终来到这里正是因为一个难以追踪的问题。你真的应该检查 `obj && typeof obj.then == 'function'` ,因为它适用于所有类型的 Promise,并且实际上是规范推荐的方式以及实现/polyfills 使用的方式。例如,原生 `Promise.all` 将适用于所有 `then`ables,而不仅仅是其他原生 Promise。你的代码也应该如此。所以 `instanceof Promise` 并不是一个好的解决方案。 (2认同)
  • 错的是问题,而不是答案。正确的问题是“我如何判断一个对象是否是*thenable*?使用鸭子类型,人们本质上不应该关心对象是什么类型。 (2认同)
  • 后续 - 更糟糕的是:在node.js 6.2.2上只使用原生承诺我现在正在尝试调试一个问题,其中`console.log(typeof p,p,p instanceof Promise);`产生这个输出:`object Promise {<pending>} false`.正如你所看到的那样,这是一个承诺 - 但是`instanceof Promise`测试会返回`false`吗? (2认同)
  • 对于不同领域的承诺,这将失败。 (2认同)

uno*_*obf 42

if (typeof thing.then === 'function') {
    // probably a promise
} else {
    // definitely not a promise
}
Run Code Online (Sandbox Code Playgroud)

  • @mrBorna `thing?.then` 中的 `?` 处理未定义的检查。这称为“可选链”。了解更多:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining (6认同)
  • 如果事情未定义怎么办?你需要通过事物&&来防范这一点...... (3认同)
  • 答案实际上回答了问题,而不是转向其他指导。谢谢! (3认同)
  • 不是最好的,但绝对是很有可能的;还取决于问题的范围。100% 防御性编写通常适用于开放式公共 API 或您知道数据的形状/签名完全开放式的情况。 (2认同)

Bog*_*ann 15

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

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

Call荷兰国际集团toString直接从Object.prototype返回一个原生字符串表示,其是给定对象类型的"[object Promise]"在我们的例子.这确保了给定的对象

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


LEQ*_*ADA 9

并非完整问题的答案,但我认为值得一提的是,在Node.js 10 isPromise中添加了一个名为util的新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
Run Code Online (Sandbox Code Playgroud)


小智 6

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

!!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function';
Run Code Online (Sandbox Code Playgroud)

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

  • 为什么我们需要obj ==='功能'条件btw? (3认同)

Ste*_*gin 6

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

async myMethod(promiseOrNot){
  const theValue = await promiseOrNot()
}
Run Code Online (Sandbox Code Playgroud)

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

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


Mur*_*one 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;
}
Run Code Online (Sandbox Code Playgroud)

更多信息:https : //www.typescriptlang.org/docs/handbook/advanced-types.html


mur*_*zel 5

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

function isPromise(value) {
  return Boolean(value && typeof value.then === 'function');
}
Run Code Online (Sandbox Code Playgroud)

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


Red*_*edu 5

为了避免比较而将可能的同步value推入其中的任何操作都会将您的代码变成本来可以避免的异步。Promise.resolve(value)有时您在那个阶段并不想要它。您想知道在微任务队列中的某些早期解决方案咬住您之前评估的结果吗?

一个人可能会这样做;

var isPromise = x => Object(x).constructor === Promise;
Run Code Online (Sandbox Code Playgroud)

我根据我能想到的一些边缘情况检查了它,它似乎有效。

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
Run Code Online (Sandbox Code Playgroud)

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