检查函数是否为jQuery ajax请求

5

我正在编写一个ajax队列,并且想要确保函数的类型(以对象形式提供)实际上是一个ajax请求,以便可以在其上调用.done/.fail/.always方法。我该如何做到这一点?


问题中可以包含 js 吗? - guest271314
你期望的值与 jQuery promises 不同吗? - MinusFour
5个回答

5
我希望确保函数类型(以对象形式呈现)实际上是一个ajax请求,这样就可以在其上调用.done/.fail/.always。
jQuery ajax 请求对象(jqXHR)不是函数。在 jQuery v1.12.0(我手边检查版本),它们是添加属性的普通对象(例如,没有特殊构造函数),因此您不能使用instanceof来查看它们是否是jqXHR对象。
您可以测试您得到的对象中是否存在done、fail和/或always。
if (obj.done && obj.fail && obj.always) {
    // It's probably a jqXHR
}

或者如果你想更加彻底,你可以确保它们是函数:

if (typeof obj.done == "function" &&
    typeof obj.fail == "function" &&
    typeof obj.always == "function") {
    // It's probably a jqXHR
}

这是“鸭子类型”的一个例子:它像鸭子一样嘎嘎叫,因此我们假设它是一只鸭子。
如果你想尽量限制它只使用jqXHR对象而不是其他具有这些函数的对象,可以检查它们是否有其它函数/属性,比如getAllResponseHeaders等。

2
我以前用过这个:
if(data && $.isFunction(data.promise)) {
...
}

我想确保函数类型(包含在对象中)实际上是一个ajax请求,以便可以在其上调用.done/.fail/.always方法。
来自jQuery.ajax()文档: $.ajax()返回的jqXHR对象自jQuery 1.5起实现了Promise接口,使它们具有Promise的所有属性、方法和行为(有关更多信息,请参见Deferred对象)。
jqXHR对象可用的Promise方法包括:
- jqXHR.done(function(data, textStatus, jqXHR){}):这是成功回调选项的一种替代构造。.done()方法替换了已弃用的jqXHR.success()方法。有关实现细节,请参阅deferred.done()。 - jqXHR.fail(function(jqXHR, textStatus, errorThrown){}):这是错误回调选项的一种替代构造。.fail()方法替换了已弃用的.error()方法。有关实现细节,请参阅deferred.fail()。 - jqXHR.always(function(data|jqXHR, textStatus, jqXHR|errorThrown){}):这是完成回调选项的一种替代构造。.always()方法替换了已弃用的.complete()方法。
  1. 有什么方法可以检查一个变量是否是真正的 jqXHR 吗?
  2. 如何判断一个对象是否是 jQuery 的 Promise/Deferred?

1
检查某个东西是否为 Promise,或者在 jQuery 的情况下是 Deferred,可以通过检查该对象是否为“thenable”来完成,即它是否具有 then() 方法。
var xhr = $.ajax({url:'...'});

if (typeof xhr === 'object' && typeof xhr.then === 'function') ...

这将适用于任何承诺(也是A+),特别是检查faildonealways方法,这些方法与jQuery ajax调用始终相关,请参见T.J的答案。

对象可能具有then属性,但不一定是$.ajax()请求。 “我想确保函数类型(包含在对象中)实际上是一个ajax请求”。 - guest271314
如果在jQuery中有一个then方法,那么它就是一个“thenable”Deferred/Promise,并且即使它不是一个ajax调用,它也具有通常的回调函数。 - adeneo
.done.fail.always是deferred API的一部分,因此不仅限于ajax请求。 - MinusFour
问题似乎是想确定返回的对象是否是一个 $.ajax() 请求,而不仅仅是具有 then 属性?请参见 OP 在 _"我想确保函数类型(包含在对象中)实际上是一个 ajax 请求"_。 - guest271314
如果它应该仅限于ajax,可以像T.J.上面所述那样检查仅限于ajax调用的特定属性,例如setRequestHeader等。 - adeneo

1

尝试检查 status 属性,调用 .state() 函数

if (object.status && (obj.state() === "resolved" || obj.state() === "rejected")) {
      if (obj.status === 200) obj.done(success)
      else obj.fail(err)
} else {
  // do other stuff
}

或者,使用.ajaxComplete(),它应该在完成$.ajax()请求时调用

所有ajaxComplete处理程序都会被调用,无论完成了什么Ajax请求。如果必须区分请求,请使用传递给处理程序的参数。每次执行ajaxComplete处理程序时,都会传递事件对象、XMLHttpRequest对象和用于创建请求的设置对象。

$(document).on("ajaxComplete", function(event, xhr, settings) {
   // do stuff
})

@adeneo // 做其他的事情;可以在else语句中使用$.when(obj).always()来处理既没有被明确地完成也没有被拒绝的对象。 - guest271314

1

虽然这是一个老问题,但我认为所有答案都不够令人满意。如果将来有人真的想检查传递的对象是否为 Promise,请尝试使用此函数。

function isPromise (obj) {
    const normal = !!obj && typeof obj === 'object' &&
                   ((obj.constructor && obj.constructor.name === 'Promise') || typeof obj.then === 'function');

    const fnForm = !!obj  && (typeof obj === 'function') && 
                   ((obj.name === 'Promise') || (typeof obj.resolve === 'function') && (typeof obj.reject === 'function'));

    return normal || fnForm;
}

与ES6 Promise、Bluebird和jQuery ajax兼容。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接