- Recipe: Setting Up an Example Server in Node.js
- Recipe: Performing a GET Request
- Recipe: Loading HTML Directly
- Recipe: Handling the Result by Using Promises
- Recipe: Handling Server Errors
- Recipe: Catching Page-not-Found Results
- Recipe: Handling Page Redirects
- Recipe: Setting Request Timeouts
- Recipe: Passing HTTP Headers
- Example: Validating Form Input on the Server Side
- Recipe: Loading XML
- Recipe: Listening to AJAX Events
- Recipe: Reading JSONP from an External Server
- Summary
Recipe: Handling the Result by Using Promises
In Listing 5.2, you saw a callback handler being passed to the get() method to be called after a successful result from the AJAX request. The advantage of callbacks is asynchronous execution of code. The browser remains responsive while the AJAX request is working in the background. However, when you have many callbacks, the code starts looking like a Christmas tree. It is a callback inside a callback inside a callback. And what about failures?
Promises can solve this problem. Understanding promises involves some theory. First, let’s explore how they work by looking in Listing 5.4.
Listing 5.4. Demonstrating done(), fail(), and always()
00 <!DOCTYPE html> 01 02 <html lang="en"> 03 <head> 04 <title>The done() fail() always() function</title> 05 </head> 06 <body> 07 08 <h2>Press the button to perform the request.</h2> 09 10 <button id="trigger">GET</button> 11 <br> 12 <div id="target"> 13 14 <script src="https://code.jquery.com/jquery-1.7.2.min.js"></script> 15 16 <script> 17 // please externalize this code to an external.js file 18 $(document).ready(function() { 19 20 $('#trigger').click(function() { 21 22 // avoid error() success() complete() 23 // those are deprecated in jQuery 1.8 24 // use done() fail() always() instead 25 26 $.ajax({url:' 02a-test-values.json', dataType: 'json'}) 27 .done (function(data) { 28 $('#target').append('The returned value is: ' 29 + data.name + '<br>'); 30 }) 31 .fail(function() { 32 $('#target').append('The AJAX call failed.<br>'); 33 }) 34 .always(function() { 35 $('#target').append('finished anyway.'); 36 }); 37 }); 38 }); 39 </script> 40 </body> 41 </html>
Notice in this script that chained functions provide callbacks after calling the ajax() function. This is possible because ajax() returns a promise object. A promise is a safe version of a deferred object. Deferred objects are discussed in Chapter 11, “Creating Plugins.” The difference is that a promise does not expose the internals of a deferred. Then, what does a promise do?
When you call the done() function with a callback handler and the ajax() request has not yet returned, the callback is stored in a queue. Once the ajax() request returns and the result is successful, all the queued callbacks under done() are called. When you call the done() function with a callback handler after the ajax() request has returned, if the result was successful, the callback is executed right away.
Callbacks passed to fail() and always() are handled similarly. Only fail() executes when the result was unsuccessful, of course.
There is a shorthand notation for done() and fail() called then(). The then() function takes two arguments: one callback in case of success and one in case of failure. The following snippet shows how you can use it to replace the done() and fail() methods used in Listing 5.4:
$.ajax({url:'02a-test-values.json', dataType: 'json'}) .then( function(data) { $('#target').append('The returned value is: ' + data.name + '<br>'); }, function() { $('#target').append('The AJAX call failed.<br>'); } );