OneManBand
OneManBand

Reputation: 558

JQuery Execution Order of Deferred Object Callback Hooks (Promise vs. Complete)

I have a locally hosted project with a view that makes an AJAX request to the server. The code is duplicated in this jsfiddle, sans the URL and data params which are replaced w/ jsfiddle test data to mimic the AJAX request.

(function demo(iteration) {
    count = iteration || 0;
  
  if (count < 3) {
    $.when(testPromise(count).promise())
        .done(function () {
        doSomething();
        })
      .always(function () {
        demo(count + 1);
        });
  }
})();

function doSomething() {
    console.log("something!");
}

function testPromise(iteration) {
  var deferred = $.ajax({
    type: 'POST',
    url: '/echo/json/',
    data: {
      json: JSON.stringify({ "data": "Data!" }),
      delay: 0.1
    },
    dataType: 'json',
    beforeSend: function () {
            console.log("Before Send: " + iteration);
    },
    success: function(response) {
      console.log("Success: " + iteration);
    },
    error: function() {
        console.log("Error: " + iteration);
    },
    complete: function () {
        console.log("Complete: " + iteration);
    }
  });
  
  return deferred;
}

Now, the Jsfiddle makes the following print statements:

jsfiddle output

However, my local code makes an alternative set of print statements:

local output

You'll notice that the jsfiddle consecutive AJAX requests are issued and completed in order, but the local output shows that consecutive requests are issued before the previous one completes: Before Send: 1; Complete: 0 and Before Send: 2; Complete: 1. That is, the Promise callback and Complete callback are not handled in the same order for these two environments.

According to http://api.jquery.com/jquery.ajax/,

The callback hooks provided by $.ajax() are as follows:

  1. beforeSend callback option is invoked.
  2. error ...
  3. dataFilter ...
  4. success callback option is invoked, if the request succeeds.
  5. Promise callbacks — .done(), .fail(), .always(), and .then() — are invoked, in the order they are registered.
  6. complete callback option fires, when the request finishes, whether in failure or success.

Besides the list order, the documentation does not really indicate whether the order of these callbacks is guaranteed and I would suppose that the order is actually not guaranteed given that the jsfiddle and my local code do not reconcile.

So what is happening under the covers to produce these two different results? And suppose I wanted my local code to behave like the jsfiddle (Complete handled before Promise) - what changes can I make to accomplish this?

Thanks in advance -

As a sidenote, I am aware that the following $.when() functionality can be achieved via the AJAX .complete() handler. I have intentionally made the AJAX function agnostic to the conditions for which it would need to be called as the end goal I have is to make a generic queue'ing module which will handle queue processing and call a given deferrable function as necessary. So, the AJAX .complete() method is not available to me for this purpose.

$.when(testPromise(count).promise())
    .done(function () {
        doSomething();
    })
    .always(function () {
        demo(count + 1);
    });

Upvotes: 0

Views: 400

Answers (1)

HumbleRat
HumbleRat

Reputation: 26

jQuery Deferred was updated in version 3.0 (https://blog.jquery.com/2016/06/09/jquery-3-0-final-released/), so making sure your jQuery version is the same as on the fiddle (3.2.1) may help.

Upvotes: 1

Related Questions