Javascript 如何判断对象是否是jQuery承诺/延迟?

Javascript 如何判断对象是否是jQuery承诺/延迟?,javascript,jquery,jquery-deferred,Javascript,Jquery,Jquery Deferred,我有一个只接受一个参数的函数。我需要知道这个参数是jQueryPromise还是Deferred对象。如果不是,那么该值可能是任何类型的,并且具有任何属性,因此仅针对promise方法的存在是不安全的 下面是我希望函数如何运行的示例: function displayMessage(message) { if (message is a Promise or Deferred) { message.then(displayMessage); } else { alert(

我有一个只接受一个参数的函数。我需要知道这个参数是jQuery
Promise
还是
Deferred
对象。如果不是,那么该值可能是任何类型的,并且具有任何属性,因此仅针对promise方法的存在是不安全的

下面是我希望函数如何运行的示例:

function displayMessage(message) {
  if (message is a Promise or Deferred) {
    message.then(displayMessage);
  } else {
    alert(message);
  }
}
注意承诺的递归处理:如果一个承诺是用另一个承诺值解析的,我们不显示它,而是等待它被解析。如果它再次承诺,请重复


这一点很重要,因为如果不是这样,我只能使用:

这将正确处理价值观和价值承诺

displayMessage("hello");                            // alerts "hello"
displayMessage(jQuery.Deferred().resolve("hello")); // alerts "hello"
…但一旦我们得到价值承诺,它就会崩溃:

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


jQuery。当
能够判断某个值是否为承诺时,显然这是可能的。如何检查?

快速而肮脏的解决方案是测试对象是否具有
功能,然后
功能:

if (typeof message.then === 'function') {
    //assume it's a Deferred or fits the Deferred interface
} else {
    //do other stuff
}
jQuery。当
能够判断某个值是否为承诺时,显然这是可能的

这是错误的。jQuery本身无法检查对象是否是完全准确的承诺。如果您查看
jQuery的源代码,当
时,您可以看到它所做的一切是:

jQuery.isFunction(firstParam.promise)
如果要返回的对象有自己的
.promise()
方法,
jQuery。当
将出现错误时:

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

jQuery.when(trickyValue).then(function(obj) {
  alert(obj.value);
});
这会抛出
类型错误:对象3没有方法“then”
,因为jQuery假定该对象是一个承诺,并信任其
.promise()
方法的值

这可能是不可能正确解决的。promise对象被创建为
jQuery.Deferred
()中的对象文本。它没有原型,也没有任何其他可以用来区分它的真正独特的特性

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

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
将函数转换为字符串可以得到它的源代码,所以这里我将比较
的源代码。然后将新
延迟
对象的
方法和我感兴趣的值的源代码。您的值不会有一个与
jQuery.Deferred
Promise
1完全相同的源代码的
.then
方法

一,。除非你在一个充满敌意的环境中跑步,否则你可能应该放弃


如果您对jQuery承诺不特别感兴趣,但希望检测任何类型的承诺,包括来自ECMAScript 6的内置承诺,则可以测试value是否为对象并具有
,然后
方法:

if (typeof value === 'object' && typeof value.then === 'function') {
  // handle a promise
} else {
  // handle a concrete value
}
这是ES6中定义的几个承诺处理函数的方法。您可以看到以下部分引用的描述:

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

[……]

  • 如果类型(分辨率)不是对象,则
  • 回报兑现承诺(承诺、决议)
  • 然后让我们获得(分辨率,
    “然后”
  • 如果这是一个突然的完成,那么
  • 返回RejectPromise(promise,然后是[value]])
  • 然后将操作设为。[[value]]
  • 如果IsCallable(thenAction)为false,则
  • 回报兑现承诺(承诺、决议)
  • 执行排队作业(
    “PromiseJobs”
    ,PromiseSolvetheEnableJob,«‍承诺、决议、行动»)

  • 请看一下运算符的实例:@MikeMcCaughan不幸的是,似乎没有一个公开的
    Promise
    类型可以使用它。是否
    displayMessage
    用于字符串/延迟/承诺以外的类型?@zzzzBov是。这是一个简化的示例,我意识到它并没有解决这个问题,但在我的实际代码中,这是一个通用函数,可以处理任何类型的数据。@Swarm,那么为什么不使用两个单独的方法呢?一个用于延迟数据转储,另一个用于执行数据转储?我对此表示反对,因为我只是想提及jQuery在幕后是如何实现的,但我不能批准该解决方案,因为承诺可以而且应该由其他库创建,例如or(甚至!),而您的解决方案将无法与它们一起工作。在我看来,jQuery解决方案是可以的。也许,除了
    .promise
    (例如
    .then
    )之外,我们可以检查是否存在更多函数,我认为这就足够了。angularJS promises使用then()方法,所以这对我有帮助。jquery的when()在我的情况下不起作用。这是一个在Promissions/a+规范中明确定义的“thenable”概念:@Jeremy Banks,你的意思是大幅修改我的答案吗?如果是这样的话,在这样做之前至少留下评论是一种常见的礼貌。我不同意,而且经常这样做。考虑到编辑可以很容易地回滚,我认为对于用户来说,更有效率的做法是感到有权进行更改,用维基百科的说法“大胆编辑”,而不是担心在我们应该将其视为社区资源时踩到“所有者”的脚。相反,我觉得在你的回答中加入这一点是一种礼貌,因为这是对你所描述的方法的澄清,而不是试图为自己辩护。如果你不喜欢这一改变,那么它只存活了八分钟。@JeremyBanks,为了证实这一点,你强烈反对将你对作者的帖子所做的重大改变通知作者是一种常见的礼貌,这可能会对他们的声誉造成负面影响?我没有说你不应该做出改变,我只是要求你重新评估你是如何做出改变的。
    if (typeof value === 'object' && typeof value.then === 'function') {
      // handle a promise
    } else {
      // handle a concrete value
    }