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 secondsr2.php
- 1 secondr3.php
- 3 secondsThe 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:
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
:
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:
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.
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.
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 = $.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With