Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jquery - usage of .done(), .then() and .when() for making ajax requests in a given order

I've been doing a lot of reading about Promises in jquery and avoiding "callback hell" when making multiple ajax requests.

I feel though even after reading all this, there's no simple answer being given to what to use - in terms of .done(), .then() and .when() - in terms of chaining the requests.

I've tried to construct the most basic example to illustrate my point. The code below works exactly as I want it to, but the only thing this relies on is .done() and I can't see where other methods (such as .then() or .when()) fit into this.

So I have created 3 PHP scripts and used PHP's sleep method to artificially delay how long these scripts take to complete. The delays are set as follows:

  • r1.php - 5 seconds
  • r2.php - 1 second
  • r3.php - 3 seconds

The script itself is as simple as this:

<?php
    // r1.php
    echo "starting r1.php \n";
    sleep(5); // Delay execution. Varies as described above for each script
    echo "ending r1.php \n";
?>

So if these were run in parallel, the order they'd complete in would be r2.php, r3.php, then r1.php.

But what if we wanted to run them in order (r1.php, r2.php, r3.php) and have jquery wait until each ajax request was made before going on to the next? For example if something in r2.php depends on the result of r1.php etc.

I've written the following - which does exactly that:

$(document).ready(function() {
   $.ajax({
        url: 'ajax/r1.php',
        method: 'get'
   }).done(function(response1) {
       console.log('After r1.php\n');
       console.log(response1);

       $.ajax({
            url: 'ajax/r2.php',
            method: 'get'
       }).done(function(response2) {
           console.log('After r2.php\n');
           console.log('response1:' + response1);
           console.log(response2);

           $.ajax({
                url: 'ajax/r3.php',
                method: 'get'
           }).done(function(response3) {
               console.log('After r3.php\n');
               console.log('response1:' + response1);
               console.log('response2:' + response2);
               console.log(response3);
           });

       });
   });

});

As you can see, the requests are completing in order, and taking the time specified in each PHP script:

enter image description here

Furthermore, due to the scope in which the callbacks are running I can access, for example, response1 (the output of r1.php) in the callback that handles r3.php:

enter image description here

My question is: Under what circumstances are any functions other than .done() (such as .then() or .when() - which are mentioned in countless resources) actually needed to do this type of thing? When would you even need .then() or .when() for this type of scenario?

As far as I understand, .done() is Promise-compatible. I've even replaced .done() with .then() in the code above and the results are exactly the same.

I have read all of the following but I feel like all of these are complicating the issue, of how to run ajax requests in order with jquery:

  • jQuery deferreds and promises - .then() vs .done()
  • How do I chain three asynchronous calls using jQuery promises?
  • https://medium.com/coding-design/writing-better-ajax-8ee4a7fb95f

Please can someone explain this in a way beginners can understand? I am using jquery 3.2.1 so would like a response that's specific to jquery, not vanilla JavaScript.

I originally asked this question but I feel it was badly worded and didn't include enough code. So I've mocked up the code given here to illustrate the exact problem.

like image 902
Andy Avatar asked Aug 20 '18 14:08

Andy


People also ask

What is the use of jQuery AJAX method ()?

jQuery 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.

Which method is used on the returned object of AJAX () method if the AJAX call fails?

If an AJAX request fails, you can react to the failure inside the callback function added via the fail() function of the object returned by the $. ajax() function. Here is a jQuery AJAX error handling example: var jqxhr = $.

What is the difference between done and success in AJAX?

success is the callback that is invoked when the request is successful and is part of the $. ajax call. done is actually part of the jqXHR object returned by $. ajax() , and replaces success in jQuery 1.8.


1 Answers

The .done() method is only called when the Promise resolves (as opposed to .fail(), which is called when the Promise is rejected).

The .then() method accepts a resolved and a rejected callback and is equivalent to using done/fail together, such that:

$.ajax().then(resolvedCallback(), rejectedCallback());

Is equivalent to

$.ajax().done(sucess()).fail(failure());

The difference being that multiple .then() can more easily be chained together for more complicated Promise resolution.

The .when() method allows you to encapsulate some logic in a Promise/Deffered/Thenable so that you can use .then(), .done(), and .fail() can be used. This is useful if you have some complex or long running logic you want to execute and need to wrap it in a Promise/Deferred easily. It also make it easier to read:

$.when(function(){/*I do something that takes a while*/})
 .then(function(){/*I succeed*/},
       function(){/*I fail*/})
 .then( ... )
 .then( ... )
 ...

You can then end the chain in an .always() to clean up any sort of result or perform some action that must always happen at the end of your chain, regardless of whether or not your promises resolved or were rejected.

Edit: Putting It All Together

Using .when(), we can have code wait unit a number of things are complete before proceeding:

function fetchMe(url) {
    return $.ajax({
        url: url,
        method: 'get'
   });
}

$.when(fetchMe('ajax/r1.php'), fetchMe('ajax/r2.php'), fetchMe('ajax/r3.php'))
 .then(function(r1, r2, r3) { // Resolve
    console.log('response1: ' + r1.data);
    console.log('response2: ' + r2.data);
    console.log('response3: ' + r3.data);
 }, function(){ // Reject!
    console.log('Something broke!');
 });

In this example, fetchMe() returns the Promise from the $.ajax() call. Using .when(), we tell the script to wait for all three of these to complete before proceeding to the .then(). The input of the resolve method takes deferred items in the order they are in the .when() and, from there, we can retrieve the data from the request.

like image 167
Justin Pearce Avatar answered Oct 20 '22 14:10

Justin Pearce