简体   繁体   English

如何判断对象是否为jQuery Promise / Deferred?

[英]How can I tell if an object is a jQuery Promise/Deferred?

I have a function that takes a single argument. 我有一个函数,只需一个参数。 I need to be able to tell if this argument is a jQuery Promise or Deferred object. 我需要能够判断这个参数是jQuery Promise还是Deferred对象。 If not, then the value may be of any type and have any properties, so it's not safe to just just for the presence of the promise methods. 如果没有,那么该值可以是任何类型并且具有任何属性,因此仅仅因为promise方法的存在是不安全的。

Here's an example of how I'd like my function to behave: 这是一个我希望我的函数表现如何的例子:

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

Notice the recursive handling of promises: if a promise is resolved with another promise value we don't display it, we wait for it to be resolved. 注意promises的递归处理:如果使用另一个promise值解析promise而我们不显示它,我们等待它被解析。 If it returns yet another promise, repeat. 如果它返回另一个承诺,重复一遍。


This is important because if this were not the case, I would just be able to use jQuery.when : 这很重要,因为如果不是这种情况,我只能使用jQuery.when

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

This would handle values and promises of values correctly... 这将正确处理值的值和承诺......

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

...but once we get to promises of promises of values, it breaks down: ......但是一旦我们接受了价值承诺的承诺,它就会崩溃:

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

jQuery.when is able to tell if a value is promise, so apparently it is possible. jQuery.when能够判断一个值是否是promise,所以显然它是可能的。 How can I check? 我怎么检查?

jQuery.when is able to tell if a value is promise, so apparently it is possible. jQuery.when能够判断一个值是否是promise,所以显然它是可能的。

This is mistaken. 这是错误的。 jQuery itself is not able to check if an object is a promise with complete accuracy. jQuery本身无法检查对象是否是完全准确的承诺。 If you look at the source of jQuery.when in the jQuery source viewer you can see that all it does is this: 如果你在jQuery源代码查看器中查看 jQuery.when 的源代码,你可以看到它所做的就是:

jQuery.isFunction(firstParam.promise)

If the object you are returning has its own .promise() method, jQuery.when will misbehave: 如果你要返回的对象有自己的.promise()方法, jQuery.when将会出错:

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

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

This throws TypeError: Object 3 has no method 'then' , because jQuery assumes the object is a promise and trusts the value of its .promise() method. 抛出TypeError: Object 3 has no method 'then' ,因为jQuery假定对象是一个promise并且信任它的.promise()方法的值。

This is probably impossible to solve properly. 这可能无法正确解决。 The promise object is created as an object literal inside of jQuery.Deferred ( view source ). promise对象在jQuery.Deferredview source )中创建为对象文字。 It has no prototype, nor any other truly unique properties that could be used to distinguish it. 它没有原型,也没有任何其他真正独特的属性可用来区分它。

However, I can think of a hacky solution that should be reliable as long as only one version of jQuery is in use: 但是,只要只使用一个版本的jQuery,我就能想到一个应该可靠的hacky解决方案:

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

Converting a function to a string gives you its source code, so here I am comparing then source of the .then method of a new Deferred object to that of the value I'm interested in. Your value is not going to have a .then method with exactly the same source code as a jQuery.Deferred or Promise 1 . 将函数转换为字符串会给你它的源代码,所以在这里我将新的Deferred对象的.then方法的源与我感兴趣的值的源进行比较。你的值不会有.thenjQuery.DeferredPromise 1完全相同的源代码的方法。

1. Unless you're running in a hostile environment, in which case you should probably give up. 1.除非你在恶劣的环境中,在这种情况下,你或许应该放弃竞选。


If you aren't specifically interested in jQuery promises, but would like to detect any type of Promise including the built-in ones from ECMAScript 6, you can test if value is an object and has a then method: 如果你对jQuery promises没有特别的兴趣,但是想要检测任何类型的Promise,包括来自ECMAScript 6的内置的Promise,你可以测试value是否是一个对象并且有一个then方法:

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

This is the approach by several Promise-handling functions defined in ES6. 这是ES6中定义的几个Promise处理函数的方法。 You can see this described in the specification of the resolve(...) functions , partially quoted below: 您可以resolve(...)函数的规范中看到这一点,部分引用如下:

When a promise resolve function F is called with argument resolution , the following steps are taken: 当使用参数解析调用promise resolve函数F时 ,将执行以下步骤:

[...] [...]

  1. If Type( resolution ) is not Object, then 如果Type( resolution )不是Object,那么
    1. Return FulfillPromise( promise , resolution ). 返回FulfillPromise( 承诺解决方案 )。
  2. Let then be Get( resolution , "then" ). 然后让Get( 分辨率"then" )。
  3. If then is an abrupt completion, then 如果那时突然完成,那么
    1. Return RejectPromise( promise , then .[[value]]). 返回RejectPromise( 承诺然后 。[[value]])。
  4. Let thenAction be then .[[value]]. 那么 接下来是动作。[[value]]。
  5. If IsCallable( thenAction ) is false , then 如果IsCallable( thenAction )为false ,那么
    1. Return FulfillPromise( promise , resolution ). 返回FulfillPromise( 承诺解决方案 )。
  6. Perform EnqueueJob ( "PromiseJobs" , PromiseResolveThenableJob, «‍promise, resolution, thenAction» ) 执行EnqueueJob( "PromiseJobs" ,PromiseResolveThenableJob, «promise,resolution,thenAction»

The quick-and-dirty solution is to test if the object has a then function: 快速和肮脏的解决方案是测试对象是否具有then函数:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM