web-dev-qa-db-ja.com

オブジェクトがPromiseであるかどうかはどうすればわかりますか?

ES6 Promiseか、Bluebird Promiseか、Q Promiseかなど。

与えられたオブジェクトがPromiseであるかどうかを確かめるためにどうやってテストするのですか?

259
theram

約束の図書館がどのように決めるか

もしそれが.then関数を持っていれば - それは only 標準のライブラリが使う約束です。

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

specification を見てください。

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

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

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

どのようにあなたが決めるべきですか

代わりにPromise.resolve(x)(QのQ(x))を呼び出すべきではありません。 always は任意の値または外部のthenableを信頼できる約束に変換します。これらのチェックを自分で実行するよりも安全で簡単です。

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

テストスイート :Dからいつでも実行できます。

271

何かが不必要にコードを複雑にするかどうかをチェックするには、単にPromise.resolveを使います。

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

})
130
Esailija

ここに私の最初の答えがあります。それはそれ以来、約束をテストする方法として 仕様で承認 になっています。

Promise.resolve(obj) == obj

これは、 アルゴリズムPromise.resolveがifおよびonly ifそれは仕様の定義による約束です。

ここには別の答えがありますが、これは以前はこう言っていましたが、その時点でSafariで動作しなかったときに別の答えに変更しました。それは1年前でしたが、これはSafariでも確実に機能します。

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

78
jib

更新:これは最善の解決策ではなくなりました。投票してください 私の他の答え 代わりに。

obj instanceof Promise

それをするべきです。これはネイティブのes6の約束でのみ確実に動作するかもしれないことに注意してください。

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

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

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

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

CallObject.prototypeからtoStringに直接アクセスすると、指定されたオブジェクトタイプの ネイティブ文字列表現 が返されます。この場合は"[object Promise]"です。これにより、指定されたオブジェクト

  • ..:などの誤検知を回避します。
    • 同じコンストラクター名(「約束」)を持つ自己定義オブジェクトタイプ。
    • 指定されたオブジェクトの自己記述toStringメソッド。
  • 複数の環境コンテキスト(iframeなど)で動作します instanceofとは対照的に またはisPrototypeOf

ただし、 タグがSymbol.toStringTagで変更された の特定の ホストオブジェクト は、"[object Promise]"を返すことができます。これは、プロジェクトに応じて意図した結果である場合とそうでない場合があります(たとえば、カスタムPromise実装がある場合)。


オブジェクトがnative 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 
}

仕様の this および this section に従って、関数の文字列表現は次のようになります。

"functionIdentifierFormalParameterListopt){FunctionBody} "

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

MDN:Function.prototype.toString

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

14

あなたが非同期メソッドにいるなら、あなたはこれをすることができて、どんなあいまいさも避けることができます。

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

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

その関数が今日約束を返さないが、明日がそれを返すか非同期として宣言されているなら、あなたは将来を見越しているでしょう。

6
Steven Spungin

これがコード形式です https://github.com/ssnau/xkit/blob/master/util/is-promise.js

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

thenメソッドを持つオブジェクトであれば、それはPromiseとして扱われるべきです。

6
ssnau

完全な質問に対する回答ではありませんが、Node.js 10では isPromise という新しいutil関数が追加されているかどうかを確認することに言及する価値があります。 objectがネイティブのPromiseかどうか

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

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

あなたがTypeScriptを使っているのであれば、 "type predicate"機能を使えることを付け加えたいと思います。論理検証をx is Promise<any>を返す関数でラップするだけで、型キャストを行う必要はありません。以下の私の例では、cはpromiseか、c.fetch()メソッドを呼び出してpromiseに変換したい私の型の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

5
Murilo Perrone

これは、 graphql-js パッケージが約束を検出する方法です。

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

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

2
muratgozel
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
purplecabbage