Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does jQuery.then() behave differently when using $.deferred and $.ajax

I've been trying to get my head around the jQuery Deferred object. My intention is to inspect each ajax response (success/fail). I want to do this without interfering with other code that declares a typical $.ajax().done().fail() request.

I've user the $.ajaxPrefilter() to get each ajax request before it is executed. Using the .then() method on the jqXHR object, I've managed to add a function that will be called before the .done() method placed on the original $.ajax() call

The code below will print out the following:

def done
def then
2nd ajax prefilter then
2nd ajax done
2nd ajax then
ajax done
ajax then

What I don't understand is why the prefilter step executes first. I would have expected it to have been executed last, or not at all.

The behaviour is what I want, but I don't understand why.

// this is a typical usage of deferred with two done functions added, the second via .then()
var def = $.Deferred();
def.done(function(){
    document.write("def done<br>");
});
def.then(function(){
    document.write("def then<br>");
});
def.resolve();

// this is a typical ajax request with a done function added, followed by another using .then()
$.ajax("/echo/json/").done(function(){
    document.write("ajax done<br>");
}).then(function(){
    document.write("ajax then<br>");
});

// for the third request i intercept and call the .then() method 
$.ajaxPrefilter( 
    function( options, originalOptions, jqXHR ) {
                jqXHR.then(function(data, textStatus, jqXHR){
                     document.write("2nd ajax prefilter then<br>");
                    });
            });

// create a typical ajax request. these will be executed after the prefilter .then()
$.ajax("/echo/json/").done(function(){
    document.write("2nd ajax done<br>");
}).then(function(){
    document.write("2nd ajax then<br>");
});

Thanks in advance for any help

UPDATE: ------------

From @Bergi response, the code below demonstrates how the $.ajaxPrefilter() is called before the done().

$.ajaxPrefilter( 
    function( options, originalOptions, jqXHR ) {
            document.write("prefilter function within $.ajax call<br>");
                jqXHR.then(function(data, textStatus, jqXHR){
                     document.write("2nd ajax prefilter then<br>");
                    });
            });

var functionToRunWhenDoneIsCalled = function() {
    document.write("done is called function<br>");
    return function(){
       document.write("2nd ajax done<br>");
    }
}

$.ajax("/echo/json/").done(
    (functionToRunWhenDoneIsCalled)()
).then(function(){
    document.write("2nd ajax then<br>");
});

This outputs:

prefilter function within $.ajax call
done is called function
2nd ajax prefilter then
2nd ajax done
2nd ajax then

Which answers my question about how the .then() method is attached to the deferred jqXHR object before the .done() method.

like image 608
Robin Avatar asked Apr 09 '13 16:04

Robin


People also ask

Why use jQuery Deferred?

In jQuery $. Deferred offers us an object that can stand as a proxy for a value that may or may not exist yet. This in itself might be useful - async operations like AJAX calls can return a standard object which can interrogate the status of the asynchronous operation.

What is deferred in jQuery?

Deferred() method in JQuery is a function which returns the utility object with methods which can register multiple callbacks to queues. It calls the callback queues, and relay the success or failure state of any synchronous or asynchronous function.

What is then in jQuery?

then() method in JQuery is used to add handlers which are to be called when the Deferred object is resolved, rejected, or in progress.

What is the use of AJAX () method?

The ajax() method is used to perform an AJAX (asynchronous HTTP) request. All jQuery AJAX methods use the ajax() method. This method is mostly used for requests where the other methods cannot be used.


2 Answers

In your case, there is no difference between adding callbacks with .done() or with .then(). Using only .done() would be enough.

What I don't understand is why the prefilter step executes first. I would have expected it to have been executed last, or not at all.

Callbacks are executed in the order they are added to the deferred object. And the prefilter is executed inside of $.ajax, i.e. the callback is attached even before the $.ajax call returns and your done and then handlers can be attached.

like image 190
Bergi Avatar answered Sep 19 '22 22:09

Bergi


All .then does if you don't return a deferred object is add another done fail and/or progress handler to the deferred object. with that in mind, it makes complete sense for the .then added in the pre-filter to execute before the one added after $.ajax() because the code in the pre-filter callback happened first. The callbacks get triggered first in first out.

like image 32
Kevin B Avatar answered Sep 20 '22 22:09

Kevin B