web-dev-qa-db-ja.com

オブジェクトがjQuery Promise / Deferredかどうかはどのように確認できますか?

単一の引数を取る関数があります。この引数がjQueryのPromiseまたはDeferredオブジェクトであるかどうかを判断できる必要があります。そうでない場合、値は任意のタイプであり、任意のプロパティを持つ可能性があるため、promiseメソッドが存在するだけでは安全ではありません。

関数をどのように動作させたいかの例を次に示します。

function displayMessage(message) {
  if (message is a Promise or Deferred) {
    message.then(displayMessage);
  } else {
    alert(message);
  }
}

Promiseの再帰的な処理に注意してください。promiseが表示されない別のpromise値で解決された場合、それが解決されるのを待ちます。さらに別の約束が返される場合は、繰り返します。


これが当てはまらない場合は、 jQuery.when

function displayMessage(message) {
  jQuery.when(message).then(function(messageString) {
    alert(messageString);
  });
}

これは値と値の約束を正しく処理します...

displayMessage("hello");                            // alerts "hello"
displayMessage(jQuery.Deferred().resolve("hello")); // alerts "hello"

...しかし、価値の約束の約束に達すると、それは崩壊します:

displayMessage(jQuery.Deferred().resolve(
  jQuery.Deferred().resolve("hello")
));                                                 // alerts "[object Object]"

jQuery.whenは、値が約束であるかどうかを判別できるため、明らかに可能です。どうすれば確認できますか?

_jQuery.when_は、値がpromiseであるかどうかを判断できるため、明らかに可能です。

これは間違っています。 jQuery自体は、オブジェクトが完全な精度でプロミスであるかどうかをチェックできません。 _jQuery.when_ jQueryソースビューアーで のソースを見ると、これだけであることがわかります。

_jQuery.isFunction(firstParam.promise)
_

返すオブジェクトに独自の.promise()メソッドがある場合、_jQuery.when_は正しく動作しません。

_var trickyValue = {
  promise: function() { return 3; },
  value: 2
};

jQuery.when(trickyValue).then(function(obj) {
  alert(obj.value);
});
_

これは_TypeError: Object 3 has no method 'then'_をスローします。これは、jQueryがオブジェクトがpromiseであると想定し、その.promise()メソッドの値を信頼するためです。

これはおそらく正しく解決することは不可能です。 promiseオブジェクトは、_jQuery.Deferred_( ソースの表示 )内にオブジェクトリテラルとして作成されます。プロトタイプも、それを区別するために使用できる他の真にユニークなプロパティもありません。

ただし、jQueryのバージョンが1つしか使用されていない限り、信頼できるハックソリューションを考えることができます。

_function isPromise(value) {
  if (typeof value === 'object' && typeof value.then !== "function") {
    return false;
  }
  var promiseThenSrc = String($.Deferred().then);
  var valueThenSrc = String(value.then);
  return promiseThenSrc === valueThenSrc;
}

isPromise("test");                 // false
isPromise($.Deferred());           // true
isPromise($.Deferred().promise()); // true
_

関数を文字列に変換するとそのソースコードが得られるので、ここでは、新しいDeferredオブジェクトの_.then_メソッドのソースを関心のある値のソースと比較しています。あなたの値_.then_またはPromiseとまったく同じソースコードを持つ_jQuery.Deferred_メソッドはありません1

1。 敵対的な環境で実行しているのでない限り、その場合はおそらくあきらめる必要があります。


JQueryのpromiseに特に関心はないが、ECMAScript 6の組み込みのものを含むanyタイプのPromiseを検出したい場合は、値がオブジェクトであるかどうかをテストできます。 thenメソッドがあります:

_if (typeof value === 'object' && typeof value.then === 'function') {
  // handle a promise
} else {
  // handle a concrete value
}
_

これは、ES6で定義されているいくつかのPromise処理関数によるアプローチです。これが説明されているのを見ることができます resolve(...)関数の仕様で 、以下に部分的に引用されています:

引数resolutionを指定してpromise resolve関数[〜#〜] f [〜#〜]を呼び出すと、次の手順が実行されます。撮影:

[...]

  1. Type(resolution)がObjectでない場合、
    1. FulfillPromise(promiseresolution)を返します。
  2. 次にGet(resolution_"then"_)とします。
  3. その後、突然の完了であれば、
    1. RejectPromise(promisethen。[[value]])を返します。
  4. thenActionthen。[[value]]とします。
  5. IsCallable(thenAction)がfalseの場合、
    1. FulfillPromise(promiseresolution)を返します。
  6. EnqueueJob(_"PromiseJobs"_、PromiseResolveThenableJob、"‍promise、resolution、thenAction")を実行します
32
Jeremy Banks

簡単な方法は、オブジェクトにthen関数があるかどうかをテストすることです。

if (typeof message.then === 'function') {
    //assume it's a Deferred or fits the Deferred interface
} else {
    //do other stuff
}
14
zzzzBov