オブジェクトがPromiseかどうかはどのようにしてわかりますか?


335

ES6プロミス、ブルーバードプロミス、Qプロミスなどです。

特定のオブジェクトがPromiseかどうかを確認するにはどうすればよいですか?


3
せいぜいあなたは.thenメソッドをチェックすることができますが、それはあなたが持っているものが確実に約束であることをあなたに教えないでしょう。その時点で知っているのは、Promise などの.thenメソッドを公​​開するものがあるということだけです。
Scott Offen、2015年

@ScottOffen promiseの仕様では明示的に区別されません。
Benjamin Gruenbaum、2015年

6
私のポイントは、誰でも.thenPromiseではないメソッドを公​​開し、Promiseのように動作せず、Promiseのように使用されることを意図していないオブジェクトを作成できるということです。確認.then方法は、単にオブジェクトがあればことを示していますしない持っている.then方法を、あなたはしていない約束を持っています。その逆- .thenメソッドの存在はあなた約束を持っていることを意味する-は必ずしも真実ではありません。
Scott Offen、2015年

3
@ScottOffen定義により、Promiseを特定する唯一の確立された方法は、Promiseに.thenメソッドがあるかどうかを確認することです。はい、それは誤検知の可能性がありますが、それはすべてのpromiseライブラリが依存していることを前提としています(それ信頼できるすべてのものだからです)。私が見る限り、唯一の代替策は、ベンジャミン・グルエンバウムの提案を取り入れて、それをプロミステストスイートに通すことです。しかし、これは実際の製品コードでは実用的ではありません。
JLRishe

回答:


341

Promiseライブラリの決定方法

それが.then関数を持っている場合-それが唯一の標準プロミスライブラリが使用します。

Promises / A +仕様には、then基本的に「thenメソッドを持つオブジェクト」である、able という概念があります。Promiseは、thenメソッドで何でも同化します。あなたが言及したpromiseの実装のすべてがこれを行います。

仕様を見ると:

2.3.3.3 then関数の場合、これをxとして呼び出し、最初の引数resolvePromise、2番目の引数rejectPromise

また、この設計決定の根拠についても説明します。

then表層のこの扱いにより、Promises / A +準拠のthenメソッドが公開されている限り、promiseの実装を相互運用できます。また、Promises / A +実装は、妥当なthenメソッドを使用して、非準拠実装を「同化」することもできます。

どう決めるか

あなたはいけない-の代わりに呼び出すPromise.resolve(x)Q(x)うというQに)常に任意の値または外部変換thenの信頼できる約束にできるように。これらのチェックを自分で実行するよりも安全で簡単です。

本当に確認する必要がありますか?

あなたはいつでもテストスイートを通してそれを実行することができます:D


95
すばらしい答えです。ただし、「すべきではない-代わりにPromise.resolve(x)を呼び出す」というオプションは常にオプションとは限りません。あなたが本当にしたい場合は、テスト対象が約束(は「は」かどうか、その後できる)、Promise.resolveあなたに何かを教えてくれませんし、プロセス内のオブジェクトに変換します。したがって、実際の答えは(という名前のオブジェクトが与えられた場合subject):var isPromise = typeof subject.then == 'function';
Stijn de Witt

11
-1。すべてのPromiseにはthenメソッドがありthenますが、すべてのメソッドはに属していませんPromise。したがって、あなたの発言は無効であり、質問に答えません。
Linus Oleander

18
@Oleanderこれは、文字通り、ECMAScript仕様とPromises / A +仕様で定義されている方法です。それがある場合はthenこの方法を、それは約束し、再帰的で同化されなければならないものとして扱われますPromise.prototype.thenPromise.resolve all raceまたはfulfill約束のコンストラクタのパラメータ。したがって、技術的には異なる方法でチェックできますが、言語自体は頻繁にチェックし、このようにチェックします。私はわからないものを、あなたのdownvote手段または何で始まるにコメントしている節以来、それについて間違ったのです「どう約束ライブラリが決定し、」それはそうです
ベンジャミンGruenbaum

5
@セバスチャンはそれを待ってみてください、そしてあなたは何が起こるかで驚かれることでしょう。
Benjamin Gruenbaum 2017年

14
このスレッドは読むのが面倒です。JavaScriptはアヒル型の言語です。この点で約束は奇妙ではありません。これは素晴らしい答えです。
ChrisM

168

何かが約束であるかどうかをチェックすることは、コードを不必要に複雑にします。 Promise.resolve

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

})

1
したがって、Promise.resolve は、その方法を何でも処理できますか?確かに何もありませんが、妥当なものはあると思いますか?
Alexander Mills

3
@AlexMillsはい、jQuery promiseのような非標準のpromiseでも機能します。オブジェクトに、promiseとは完全に異なるインターフェイスを持つthenメソッドがある場合、失敗する可能性があります。
エサイリヤ2016年

19
この回答は、おそらく良いアドバイスですが、実際には質問に答えるものではありません。
Stijn de Witt 2016

4
問題が実際にpromiseライブラリを実際に実装している人に関するものでない限り、質問は無効です。チェックを行う必要があるのはpromiseライブラリだけです。その後、私が示したように、常に.resolveメソッドを使用できます。
エサイリヤ2016年

4
@Esalijaこの質問は、Promiseライブラリの実装者だけでなく、関連性があり重要であるように思われます。また、実装がどのように動作する/する/する必要があるのか​​、また異なるプロミスライブラリが相互にどのように相互作用するのかを知りたいプロミスライブラリのユーザーにも関係します。特に、このユーザーは、Xが「約束」(ここでは「約束」が何を意味するか、それが問題である場合)を除いて、すべてのXに対してXを約束できるという明白な事実に大いに失望し、私は間違いなく興味を持っていますその例外の境界がどこにあるかを正確に知ることにおいて。
Don Hatch

103

これが私の元の回答です。これは、仕様書で約束をテストする方法として批准されています。

Promise.resolve(obj) == obj

これが機能するのは、仕様の定義で約束されている場合にのみ、渡された正確なオブジェクトを返す必要があることをアルゴリズムが明示的に要求するためです。Promise.resolve

私はここで別の答えを持っていますが、以前はこれを言っていましたが、そのときにSafariで機能しなかったときに別の答えに変更しました。それは1年前のことでしたが、今ではSafariでも確実に機能します。

元の回答よりも多くの人がその回答の変更された解決策に投票したことを考えると、間違っていると感じた場合を除いて、元の回答を編集したでしょう。私はこれがより良い答えだと思います、そしてあなたが同意することを望みます。


10
===代わりに使用する必要があり==ますか?
Neil S

12
これは、同じ領域にない約束に対しても失敗します。
Benjamin Gruenbaum

4
「仕様の定義によるプロミス」は、「Promise.resolve()を介して作成されたプロミスと同じコンストラクターによって作成されたプロミスがそうである」という意味であるように思われます。ポリフィルドプロミスは実際にはプロミス
VoxPelli

3
この回答は、すぐに回答から始めるのではなく、質問をどのように解釈しているかを述べることから始めると改善される可能性があります。OPは残念ながらまったく明確にしておらず、現時点でもそうではありません。 OP、ライター、リーダーは、3つの異なるページにあります。あなたが参照するドキュメントは、「引数がこのコンストラクタによって生成された約束である場合」と言っています。イタリック体の部分は重要です。それがあなたが答えている質問であると述べるのは良いことです。また、回答はこのライブラリのユーザーには役立ちますが、実装者には役立ちません。
Don Hatch、

1
この方法を使用しないでください。理由は、@ BenjaminGruenbaumの要点です。gist.github.com/reggi/a1da4d0ea4f1320fa15405fb86358cff
ThomasReggi

61

更新:これはもはや最良の答えではありません。代わりに他の回答に投票しください。

obj instanceof Promise

それを行う必要があります。これはネイティブes6 promiseでのみ確実に機能することに注意してください。

.thenここで他の回答に示されているように、shim、promiseライブラリ、またはpromiseのようなふりをしているものを使用している場合は、「thenable」(メソッドを持つもの)をテストする方が適切な場合があります。


それ以来、Safariでは機能しないことが指摘されてPromise.resolve(obj) == objます。instanceof Promise代わりに使用してください。
ジブ2015

2
これは確実に機能せず、問題を非常に追跡するのが非常に困難になりました。es6.promiseシムを使用するライブラリがあり、どこかでBluebirdを使用するとします。問題が発生します。この問題はChrome Canaryで発生しました。
ヴォーン

1
はい、この答えは実際には間違っています。私はここで、追跡が非常に困難な問題のためにここに行きました。obj && typeof obj.then == 'function'これはすべてのタイプのプロミスで機能し、実際には仕様で推奨され、実装/ポリフィルで使用される方法であるため、実際に確認する必要があります。Promise.allたとえばネイティブはthen、他のネイティブプロミスだけでなく、すべての能力で機能します。だからあなたのコードをする必要があります。したがってinstanceof Promise、良い解決策ではありません。
Stijn de Witt 2016

2
フォローアップ-もっと悪い:node.js 6.2.2でネイティブプロミスのみを使用console.log(typeof p, p, p instanceof Promise);して、次の出力を生成する問題をデバッグしようとしていますobject Promise { <pending> } false。あなたが見ることができるようにそれは申し分なく約束です-そして、instanceof Promiseテストは戻りますfalseか?
Mörre

2
これは、同じ領域ではない約束に対しては失敗します。
Benjamin Gruenbaum

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

6
物事が定義されていない場合はどうなりますか?&& ...を介してそれを防ぐ必要があります
mrBorna

最善ではないが、間違いなく非常に可能性が高い。問題の範囲にも依存します。100%防御的に書くことは、通常、オープンエンドのパブリックAPI、またはデータの形状/署名が完全にオープンエンドであることがわかっている場合に適用できます。
rob2d 2018年

17

指定されたオブジェクトがES6 Promiseであるかどうかを確認するには、次の述語を使用できます。

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

CallINGのtoString直接Object.prototype戻るネイティブ文字列表現で指定されたオブジェクト・タイプの"[object Promise]"我々の場合です。これにより、指定されたオブジェクトが

  • 次のような誤検知をバイパスします。
    • 同じコンストラクタ名( "Promise")を持つ自己定義オブジェクトタイプ。
    • toString指定されたオブジェクトの自己記述メソッド。
  • またはとは対照的に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 
}

これと仕様のこのセクションによれば、関数の文字列表現は次のようになります。

「関数識別子FormalParameterList opt){ FunctionBody }」

上記に応じて処理されます。FunctionBodyがある[native code]すべての主要なブラウザで。

MDN: Function.prototype.toString

これは、複数の環境コンテキストでも機能します。


11

完全な質問への回答ではありませんが、Node.js 10ではisPromise、オブジェクトがネイティブのPromiseであるかどうかをチェックするという、呼び出された新しいutil関数が追加されたことに言及する価値があると思います。

const utilTypes = require('util').types
const b_Promise = require('bluebird')

utilTypes.isPromise(Promise.resolve(5)) // true
utilTypes.isPromise(b_Promise.resolve(5)) // false

11

これがgraphql-jsパッケージがpromiseを検出する方法です

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

value関数の戻り値です。私は自分のプロジェクトでこのコードを使用しており、今のところ問題はありません。


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ます。


3
なぜobj === 'function'条件が必要なのですか?
アレンドルフ2017

この回答と同じように、どのオブジェクトにもメソッド「then」を含めることができるため、常にプロミスとして処理できるわけではありません。
Boghyon Hoffmann

6

使用している場合は活字体を、私はあなたが「タイプ述語」機能を使用することができることを追加したいと思います。論理検証を返す関数にラップするだけで、x is Promise<any>型キャストを行う必要がなくなります。以下の例でcは、c.fetch()メソッドを呼び出すことでプロミスまたはプロミスに変換したいタイプの1つを示しています。

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


6

非同期メソッドを使用している場合は、これを実行してあいまいさを回避できます。

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

関数がpromiseを返す場合、待機し、解決された値で戻ります。関数が値を返す場合、それは解決済みとして扱われます。

関数が今日プロミスを返さないが、明日はプロミスを返すか、非同期と宣言されている場合、あなたは将来を見据えています。


これは次のように機能します。「[awaited]値がpromiseでない場合、[await式]は値を解決済みPromiseに変換し、それを待ちます」
pqnet

これは、非同期のawait構文が代わりに使用されているものを除き、ここでは受け入れ答えに示唆されている基本的であるPromise.resolve()
B12Toaster

3
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';
}

-1

検索した後、信頼性の高い検出する方法非同期機能、あるいは約束を、私は次のテストを使用して終了しました:

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

そのPromiseインスタンスをサブクラス化して作成すると、このテストは失敗する可能性があります。これは、テストしようとしているほとんどの場合に機能します。
セラム

同意しますが、なぜ誰かが約束のサブラスを作成するのかはわかりません
Sebastien H.

fn.constructor.name === 'AsyncFunction'間違っています-何かが非同期関数であり、promiseではないことを意味します-また、人々はpromiseをサブクラス化できるため、機能することは保証されていません
Benjamin Gruenbaum

@BenjaminGruenbaum上記の例はほとんどの場合に機能します。独自のサブクラスを作成する場合は、その名前にテストを追加する必要があります
Sebastien H.

できますが、既にどのオブジェクトがあるかわかっている場合は、何かが約束であるかどうかはすでにわかっています。
Benjamin Gruenbaum

-3

ES6:

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

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

2
toStringメソッドを持つ(または上書きされた)オブジェクトは、を含む文字列を返すことができます"Promise"
Boghyon Hoffmann、2018

4
この答えは、多くの理由のために悪いです、最も明白なビーイング'NotAPromise'.toString().includes('Promise') === true
DAMD
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.