如何判断对象是否为jQuery Promise/Deferred? [英] How can I tell if an object is a jQuery Promise/Deferred?

查看:98
本文介绍了如何判断对象是否为jQuery Promise/Deferred?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有单个参数的函数.我需要能够判断此参数是jQuery Promise还是Deferred对象.如果不是,则该值可以是任何类型且具有任何属性,因此仅凭promise方法并不安全.

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. 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.

这是我希望函数运行的一个示例:

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);
  }
}

请注意对promise的递归处理:如果使用另一个promise值解析了一个promise,我们将不显示它,我们将等待其解决.如果它还返回另一个诺言,请重复.

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. If it returns yet another promise, repeat.

这很重要,因为如果不是这种情况,我将只能使用 jQuery.when :

This is important because if this were not the case, I would just be able to use 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能够判断一个值是否为诺言,因此显然是可能的.我该如何检查?


jQuery.when is able to tell if a value is promise, so apparently it is possible. How can I check?

推荐答案

jQuery.when能够判断一个值是否为诺言,因此很可能.

jQuery.when is able to tell if a value is promise, so apparently it is possible.

这是错误的. jQuery本身无法检查对象是否完全正确.如果您在jQuery源中查看jQuery.when 查看器,您可以看到它的全部功能是

This is mistaken. jQuery itself is not able to check if an object is a promise with complete accuracy. If you look at the source of jQuery.when in the jQuery source viewer you can see that all it does is this:

jQuery.isFunction(firstParam.promise)

如果您要返回的对象具有其自己的.promise()方法,则jQuery.when行为不当:

If the object you are returning has its own .promise() method, jQuery.when will misbehave:

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()方法的值.

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.

这可能无法正确解决.在jQuery.Deferred(查看源文件).它没有原型,也没有其他可以用来区分它的真正独特的属性.

This is probably impossible to solve properly. The promise object is created as an object literal inside of jQuery.Deferred (view source). It has no prototype, nor any other truly unique properties that could be used to distinguish it.

但是,我可以想到一个只要使用一个版本的jQuery的可靠解决方案就应该是可靠的:

However, I can think of a hacky solution that should be reliable as long as only one version of jQuery is in use:

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方法,该方法的源代码与jQuery.DeferredPromise 1 完全相同.

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 Promise1.

1.除非您在敌对环境中运行,否则在这种情况下,您可能应该放弃.

1. Unless you're running in a hostile environment, in which case you should probably give up.

如果您对jQuery Promise并不是特别感兴趣,但想检测任何类型的Promise,包括ECMAScript 6中的内置Promise,则可以测试value是否是一个对象并具有then方法:

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:

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

这是ES6中定义的几个Promise处理函数的方法.您可以在 >函数,部分引用如下:

This is the approach by several Promise-handling functions defined in ES6. You can see this described in the specification of the resolve(...) functions, partially quoted below:

当使用参数 resolution 调用承诺解决函数 F 时,将执行以下步骤:

When a promise resolve function F is called with argument resolution, the following steps are taken:

[...]

  1. 如果Type( resolution )不是Object,则
  1. If Type(resolution) is not Object, then
  1. 返回FulfillPromise( promise 分辨率).
  1. Return FulfillPromise(promise, resolution).

  • 然后获取(分辨率 "then" ).
  • 如果那是一个突然的完成,那么

  • Let then be Get(resolution, "then").
  • If then is an abrupt completion, then

    1. 返回RejectPromise( promise then .[[value]]).
    1. Return RejectPromise(promise, then.[[value]]).

  • thenAction then .[[值]].
  • 如果IsCallable( thenAction )为 false ,则

  • Let thenAction be then.[[value]].
  • If IsCallable(thenAction) is false, then

    1. 返回FulfillPromise( promise 分辨率).
    1. Return FulfillPromise(promise, resolution).

  • 执行EnqueueJob( "PromiseJobs" ,PromiseResolveThenableJob,«Promise,解决方案,然后采取行动»)
  • Perform EnqueueJob ("PromiseJobs", PromiseResolveThenableJob, «‍promise, resolution, thenAction»)
  • 这篇关于如何判断对象是否为jQuery Promise/Deferred?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆