There is a requirement to make multiple AJAX calls parallelly to fetch the required data and each successive call depends on the data fetched in its prior call. Since AJAX is asynchronous, one cannot control the order of the calls to be executed. Because of this behavior, there is an inconsistency in the data that will be bound to the UI.
A Real-Life Example
Our team was working on an application that integrated all the reports created using Microsoft’s Power BI into it and the end users, based on their access levels, could view the reports and other related data. We also had a User Management System in place, from where Admins could manage other Users and restrict the data that they have to access.
In one of the screens, we have a requirement to display all the Available Reports in the system in one drop-down and all the Assigned Reports to a user in the other drop-down as shown in the below image.
Here we needed to make two AJAX calls to get the data for the above drop-downs. One call will fetch the assigned reports and then the other should be called to fetch all the available reports which will be filtered out based on the data that is already fetched in the first call to get the actual available reports.
Assigned Reports = Assigned Reports
Available Reports = Total Available Reports – Assigned Reports
Because of the asynchronous behavior, sometimes, getAvailableReports() function used to hit first which was resulting in fetching the inconsistent data to the Available Reports drop-downs as shown below.
1. A Conventional Approach to this Issue
The easiest and simplest way to fix this issue is to call both the functions in sequence by nesting the getAvailableReports() into the success callback of getMappedReports() as shown in the below code
If there are multiple sequential AJAX calls to be made as shown in the below image, then the above approach makes the code less readable. This would lead to a lot of nested callbacks that have to be synchronized, which is often referred to as “callback hell.”
2. A Generic and Re-Usable Approach
- jQuery.when() provides a way to execute callback functions based on zero or more Thenable objects, usually Deferred objects that represent asynchronous events. jQuery.when() accepts deferreds (Deferred, Promise or Thenable objects)
- As of jQuery 1.5, jQuery.Ajax() is a Promise-Compatible object meaning, it will return a resolved promise object
- deferred.then() is a handler to be called when the deferred object is resolved, rejected or still in progress
But what if we have hundreds of ajax calls to be made? We need a way to convert these ajax calls from jQuery.when() into a list of arguments. That’s where apply() function comes in handy.
When we call jQuery.when() function, “this” keyword inside the function is implicitly bind to jQuery object. But when we call jQuery.when.apply(), we have to explicitly bind “this” keyword to something. And we know that the binding has to be with jQuery object, so we pass jQuery object, a.k.a., $ as the first argument.
As we know that each jQuery.ajax() will return a deferred object, we can return a list of such deferred objects as an argument to jQuery.when.apply() as shown below. Now the solution looks more clean, readable, maintainable and a re-usable one.
Promises allow you to avoid nasty tricks to synchronize parallel or sequential asynchronous functions and the need to nest callbacks inside callbacks inside callbacks. Deferred remains an incredibly powerful tool to have in your toolbox. As a professional developer, and with the increasing difficulty of your projects, you’ll find yourself using it a lot.
.promise() – https://api.jquery.com/promise/
jQuery.Deferred() – https://api.jquery.com/jquery.deferred/
jQuery.when() – https://api.jquery.com/jquery.when/
deferred.then() – https://api.jquery.com/deferred.then/
Latest posts by Anantha Kashyap M D
- Handling Sequential AJAX Calls using jQuery - June 10, 2019