AJAX is common now a days. People try to implement AJAX but fail to return the response from AJAX call successfully because they misunderstood the concept behind AJAX and the right way to do that.
Here I have tried to explain the flow and restructure the code for AJAX using deferred objects / promises to let your application work. First I have explained the problem then the meaning of AJAX and flow as well followed by the solution.
The wrong but people do:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | function fooAjax() { var result; $.ajax({ url: 'thepage', success: function(response) { result = response; } }); return result; } var result = fooAjax(); // always ends up being `undefined` |
You can see the result always ends up with undefined, the problem!
Flow and explanation of the problem:
The A in AJAX stands for asynchronous. It means receiving the response is taken out of the normal execution flow. In our code above, return result
is executed before the function you passed as success callback was even called.
Return the response from AJAX call – the right way to do
So you got the problem! To deal with it, you can either make the AJAX call synchronous or restructure code.
Option 1: SJAX call (synchronous AJAX) [never do it]
It is generally a bad idea to make AJAX calls synchronous. DON’T DO IT because at all this is really bad user experience since
- JavaScript runs in the UI thread of the browser and any long running process will lock the UI, making it unresponsive.
- JavaScript has an upper limit on the execution time and the browser will ask the user whether to continue the execution or not and he won’t be able to tell anything to browser.
- Slow connection will have worse effects.
Option 2: Restructure code
Even one of the available solutions is to modify our function to accept callback, we are focusing on better solution called deferred objects / promises as this works fine with third party code and able to deal with many callbacks.
Every AJAX method of jQuery already returns a promise which you can just return from your function and the calling code decides how to attach the callbacks:
1 2 3 4 5 6 7 8 9 | function bar() { return $.ajax(...); } bar().done(function(result) { // code depending on result }).fail(function() { // code to deal with error }); |
So now based on the above example, suppose we have the following bad code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | function deleteProduct() { return $.ajax({ url: '/product', data: { productId: $('#pid').val() action: 'delete' }, type: 'POST', dataType: 'json' }); } if (deleteProduct()) { // Tell the user that product deleted } |
This code has the asynchronous issue. $.ajax()
doesn’t freeze the code while it waits for the /product
page to delete your product on your server as well as immediately returns a jQuery AJAX Deferred object. So your statement is going to always get this Deferred object, treat that as true (product deleted). To fix this, improve the code:
1 2 3 4 5 6 7 8 9 10 11 | deleteProduct() .done(function(p) { if (p) { // Product deleted } else { // Failed to delete product } }) .fail(function(x) { // Tell the user something bad happened }); |
So now we’re still calling the /product
page on the server, but our code now properly handles the wait time for the server to respond. In the function deleteProduct() {...}
the $.ajax()
call still returns immediately with a jQuery AJAX Deferred object, but we use it to attach event listeners to .done()
and .fail()
.
In the .done() call, where the server responded with a normal response (HTTP 200), we check the object returned by the server. In this example the server is just returning true if the product gets deleted, false if not, so if (p)
is checking for true/false.
In the .fail() handler we’re dealing with something going wrong – for example if the user lost their internet connection meanwhile, or if your server went down.
That’s It! I hope you have understood well the flow of AJAX and how to use this smart tool (AJAX Deferred object) to return the response from AJAX call in the right way.