104

Is there a Java 'finally' analogue in jQuery AJAX calls? I have this code here. In my always I throw an exception, however I ALWAYS want it to go to the then() method.

    call.xmlHttpReq = $.ajax({
        url : url,
        dataType : 'json',
        type : 'GET'
    }).always(function(processedDataOrXHRWrapper, textStatus, xhrWrapperOrErrorThrown) {

       throw "something";

    }).then(function() {

        alert("i want to always run no matter what");
    });

I have tried to use done(), complete(), and the another always(), but nothing seems to work.

Here is JSFiddle :

http://jsfiddle.net/qv3t3L0m/

Oliver Watkins
  • 12,575
  • 33
  • 119
  • 225
  • just append it to `always`... – David Fregoli Apr 10 '13 at 12:16
  • 1
    You cannot catch asynchronically thrown errors it that's what you're looking for. You will need to wrap it into a `try-catch-finally` statement yourself. – Bergi Apr 10 '13 at 12:18
  • 3
    It ***Always*** goes to the always() function, that's why it's so aptly named. – adeneo Apr 10 '13 at 12:18
  • Unless jQuery handles every try/catch in a callback, `throw "something";` will simply stop code execution. – plalx Apr 10 '13 at 12:18
  • @Bergi, I'm not familiar with jQuery's promises impl, but if it's Promises/A+ compliant, then errors thrown will be passed to an errorHandler passed to then. So if he passes a second function to then, that will receive "something" as a parameter. – Frances McMullin Apr 10 '13 at 12:22
  • @DavidMcMullin: I know that, but neither is jQuery Promise/A+-compliant nor is the error thrown inside the `then`-callback (there would be no promise to reject from from an `always`-callback) – Bergi Apr 10 '13 at 12:23
  • @adeneo if you replace the THEN with an ALWAYS it will not go there. You can try it in my code. It will never reach. – Oliver Watkins Apr 10 '13 at 12:29
  • Of course not, when you throw an exception everything stops, but why would you even do that, as there are fail(), done() and always() functions readily available. – adeneo Apr 10 '13 at 12:40
  • because i am looking for a 'finally' construct like in Java. Basically i want to get the piece of code above to work. If jQuery is incapable of doing that, then I will have to find some kind of work around. The 'everything stops' nature of exception throwing is what is causing me problems. – Oliver Watkins Apr 10 '13 at 13:34
  • anyone have any ideas? I am running out of ideas :(I am thinking of just using the XMLRequest object, and not using the JQuery AJAX framework because it does not seem to work properly – Oliver Watkins Apr 10 '13 at 15:36

6 Answers6

175

See this example:

$.ajax({
        type: "GET",
        dataType: dataType,
        contentType: contentType,
        async: TRUE,
        url: $('html form:nth-child(1)').attr('action') + "?" $('html form:nth-child(1)').serialize(),
        success: function(data) {
            console.log("FUNFOU!");
        },
        error: function(data) {
            console.log("NÃO FUNFOU!");
        },
        complete: function(data) {
            console.log("SEMPRE FUNFA!"); 
            //A function to be called when the request finishes 
            // (after success and error callbacks are executed). 
        }
    });

For more informations: http://api.jquery.com/jquery.ajax/

Rafael Gomes Francisco
  • 2,193
  • 1
  • 15
  • 16
  • 45
    `.complete()` has been deprecated; use `.always()` now. http://api.jquery.com/jQuery.ajax/ – mlg Dec 22 '16 at 01:19
  • 8
    Liked for the FUNFAR verb :D – Bruno Rodrigues Jul 11 '17 at 11:57
  • 9
    @mlg: complete parameter is not deprecated, they've only deprecated .complete() callback, since now jqXHR objects implement the Promise interface. See answer to this question: https://stackoverflow.com/questions/15821141/deprecation-of-success-parameter-in-jquery-ajax – jeanie77 Sep 05 '18 at 10:39
52

.always() should work. See the The jqXHR Object section at http://api.jquery.com/jQuery.ajax/.

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

In response to a successful request, the function's arguments are the same as those of .done(): data, textStatus, and the jqXHR object. For failed requests the arguments are the same as those of .fail(): the jqXHR object, textStatus, and errorThrown. Refer to deferred.always() for implementation details.

See also http://api.jquery.com/deferred.always/

jrummell
  • 42,637
  • 17
  • 112
  • 171
17

The below suggestions will not work in jQuery, because jQuery's promise implementation does not handle errors thrown in methods passed to then. I am only leaving them here as an illustration of what could be possible if jQuery was promises/A+ compliant. As Bergi rightly points out, you will have to manually wrap your code in your own try catch block.

call.xmlHttpReq = $.ajax({
    url : url,
    dataType : 'json',
    type : 'GET'
}).then(function(processedDataOrXHRWrapper, textStatus, xhrWrapperOrErrorThrown) {

   throw "something";

}).always(function() {

    alert("i want to always run no matter what");
});

Although I'm not sure if jquery's promise supports always, an alternative would be to use then (again) and pass the same function as both successHandler and errorHandler, like this :

call.xmlHttpReq = $.ajax({
    url : url,
    dataType : 'json',
    type : 'GET'
}).then(function(processedDataOrXHRWrapper, textStatus, xhrWrapperOrErrorThrown) {

   throw "something";

}).then(function() {

    alert("i want to always run no matter what");
},
function() {

    alert("i want to always run no matter what");
});
Frances McMullin
  • 5,516
  • 2
  • 18
  • 19
  • jQuery's `then` does not catch errors in the callback. Did *you* try this? – Bergi Apr 10 '13 at 12:36
  • sorry, I tried using then->always, and having two functions in my then, but I still have the same problem. – Oliver Watkins Apr 10 '13 at 12:37
  • sincerest apologies, after looking at jquery's deferred docs I thought this would work, but I was clearly mistaken and Bergi rightly points out I should have checked in a sandbox. – Frances McMullin Apr 10 '13 at 12:40
3

Just a note for those who use jQuery 3.0 and later

Deprecation Notice: The jqXHR.success(), jqXHR.error(), and jqXHR.complete() callbacks are removed as of jQuery 3.0. You can use jqXHR.done(), jqXHR.fail(), and jqXHR.always() instead.

As in official documentation

2

There is a bug ajax is dependent on the server, need to check status with "complete" is the best, a kind of "success", "error" and others are not 100% of the PUT, POST and GET ... look at an example

$.ajax({
    url: '/api/v2/tickets/123456.json',
    ....
    ....
    ....
    complete: function(data) { 
        if (data.statusText == "success") { 
            console.log("Sent successfully");
        } else { 
            console.log("Not Sent");
        }
    }
});

Sorry bad english! Cheer ;-)

KingRider
  • 2,140
  • 25
  • 23
1

if you want one code definition for all ajax requests, you can do it like this

$(document).ajaxComplete(function () {
    console.log('ajax complete on doc');
})
sairfan
  • 970
  • 2
  • 12
  • 20