5

I am writing an ajax queue and I want to ensure that the type of function (comes in an object) is in fact an ajax request so that .done/.fail/.always can be called on it. How can I do this?

BarryBones41
  • 1,361
  • 1
  • 13
  • 30

5 Answers5

5

I want to ensure that the type of function (comes in an object) is in fact an ajax request so that .done/.fail/.always can be called on it.

jQuery ajax request objects (jqXHR) aren't functions. In jQuery v1.12.0 (the version I had handy to check), they're plain objects with properties added (e.g., no special constructor), so you can't use instanceof to see if they're jqXHR objects.

You can test whether done, fail, and/or always are present on the object you get:

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

Or if you wanted to be more thorough you might make sure they were functions:

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

This is an example of "duck typing": It quacks like a duck, so we'll assume it's a duck.

If you want to really limit it as much as you can to jqXHR objects and not other things that have those functions, you could check for other functions/properties that they have, such as getAllResponseHeaders and such.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
2

I've used this before:

if(data && $.isFunction(data.promise)) {
...
}

I want to ensure that the type of function (comes in an object) is in fact an ajax request so that .done/.fail/.always can be called on it.

From the jQuery.ajax() documentation:

The jqXHR objects returned by $.ajax() as of jQuery 1.5 implement the Promise interface, giving them all the properties, methods, and behavior of a Promise (see Deferred object for more information).

Available Promise methods of the jqXHR object include:

jqXHR.done(function( data, textStatus, jqXHR ) {}); An alternative construct to the success callback option, the .done() method replaces the deprecated jqXHR.success() method. Refer to deferred.done() for implementation details.

jqXHR.fail(function( jqXHR, textStatus, errorThrown ) {}); An alternative construct to the error callback option, the .fail() method replaces the deprecated .error() method. Refer to deferred.fail() for implementation details.

jqXHR.always(function( data|jqXHR, textStatus, jqXHR|errorThrown ) { });* An alternative construct to the complete callback option, the .always() method replaces the deprecated .complete() method.

Related question/answers:

  1. Any way to check whether a variable is a real jqXHR?
  2. How can I tell if an object is a jQuery Promise/Deferred?
Community
  • 1
  • 1
cweston
  • 11,297
  • 19
  • 82
  • 107
1

Checking if something is a promise, or in jQuery's case a Deferred, can be done by checking that the object is "thenable", i.e. that it has a then() method

var xhr = $.ajax({url:'...'});

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

This would work with any promises (also A+), to specifically check for the fail, done and always methods that a jQuery ajax call always would have, see T.J's answer.

adeneo
  • 312,895
  • 29
  • 395
  • 388
  • Object could have a `then` property though not be an `$.ajax()` request. _"I want to ensure that the type of function (comes in an object) is in fact an ajax request"_ – guest271314 Feb 01 '16 at 16:08
  • If it has a `then` method in jQuery, it's a *"thenable"* Deferred/Promise, and it has the usual callbacks even if it isn't an ajax call. – adeneo Feb 01 '16 at 16:09
  • `.done`, `.fail` and `.always` are part of the deferred api so it's not limited to ajax requests either. – MinusFour Feb 01 '16 at 16:10
  • Question appears to seek to determine if returned object is an `$.ajax()` request, not only having `then` property ? See OP at _"I want to ensure that the type of function (comes in an object) is in fact an ajax request"_ – guest271314 Feb 01 '16 at 16:10
  • And if it's supposed to be limited to only ajax, one can do as noted by T.J. above, check for specific properties only ajax calls have, like `setRequestHeader` etc. – adeneo Feb 01 '16 at 16:12
1

Try checking for status property, calling .state() function

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

alternatively, use .ajaxComplete(), which should be called at completed $.ajax() requests

All ajaxComplete handlers are invoked, regardless of what Ajax request was completed. If you must differentiate between the requests, use the parameters passed to the handler. Each time an ajaxComplete handler is executed, it is passed the event object, the XMLHttpRequest object, and the settings object that was used in the creation of the request.

$(document).on("ajaxComplete", function(event, xhr, settings) {
   // do stuff
})
guest271314
  • 1
  • 15
  • 104
  • 177
  • @adeneo `// do other stuff` ; could use `$.when(obj).always()` at `else` statement for object that is neither explicitly fulfilled or rejected – guest271314 Feb 01 '16 at 16:16
1

Old question but I think all those answers are pretty unsatisfying. If someone in the future really wants to check if a passed object is a Promise try this function.

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

works with ES6 promises, Bluebird and jQuery ajax.

oliverj
  • 41
  • 8