jQuery.when() – “Provides a way to execute callback functions based on one or more objects, usually Deferred objects that represent asynchronous events”
https://api.jquery.com/jQuery.when/
Wouldn’t it be nice to be able to know when two ajax calls are both complete – and then process the data returned from both, at the same time ?
Callbacks
Off the top of my head I would normally achieve this using a callback – and I have done so in some of my ExtJS in XPages articles. The following code snippet creates a callback that once the $.ajax call the url is complete take the data and pass it to the createGrid function. In there I could make another ajax call and then when that is complete I could process both data sets.
function getGridData(url, callback){ var dataURL = url $.ajax({ url: dataURL+"&rand="+aRandomNumber()+"&" }).done(function ( data ) { //one the data is loaded then pass it to the callback function //passed in as one of the function arguments if(callback){ callback(data) } }); } var url = location.href url = (url.indexOf('5Col')>-1) ? '5Col' : "" url = 'xRestService.xsp/byFirstNameFlat'+url+'?count=100000' var theData var theCallBack = function(theData){ createGrid(theData) } getGridData(url, theCallBack)
This kinda makes an synchronous linear usage of asynchronous calls – do this then do that
As inelegant as that it, it works. The problems really start when you have 3, 4 or more callbacks and you get a callback hell of what if something fails in the middle and you have to run back up the tree looking for a fail – not pretty.
Using jQuery.when()
Modern browsers support the Promises concept which natively allows us to do the same thing but we know what that means and not the browsers we code for today.
.when() gives us the ability to pass as many ajax calls as we like, and then create one line of code which processes all the answers together.
Example
Here is a simple REST service feed from an XPages URL (fakenames data)
http://copper.xomino.com/xomino/extjs.nsf/xRestService.xsp/byFirstNameFlat?count=5
[ { "@entryid":"1-AE3FB4C32057B87C85257C22000A83DD", "@unid":"AE3FB4C32057B87C85257C22000A83DD", "@noteid":"F5CA", "@position":"1", "@siblings":1304, "@form":"fUserName", "noteid":"NT0000F5CA", "firstname":"Alfred", "lastname":"Hall", "address":"2139 Jail Drivedd", "city":"Tremont", "state":"FL", "zip":615680, ......... } ]
Which is nice ‘n all, but if we then wanted to know what State FL was (remember this is an example)
At the same time as pulling in the person you could also pull a list of US states
http://copper.xomino.com/xomino/extjs.nsf/states.json
{ "AL": "Alabama", "AK": "Alaska", "AS": "American Samoa", "AZ": "Arizona", "AR": "Arkansas", "CA": "California", "CO": "Colorado", "CT": "Connecticut", "DE": "Delaware", "DC": "District Of Columbia", "FM": "Federated States Of Micronesia", "FL": "Florida", "GA": "Georgia", ......
From that we can then do a cross reference and display something useful.
The $.when returns each element as an Array of data so we have to get the zeroth value of each object returned to access it’s key/pairs
$.when( $.ajax({ url: "xRestService.xsp/byFirstNameFlat?count=5", dataType: "json" }), $.ajax({ url: "states.json", dataType: "json" }) ).done(function( people, states ) { for (var i=0; i < people[0].length; i++){ var person = people[0][i] var temp = "" temp=temp+person.firstname+" " temp=temp+person.lastname+" lives in " temp=temp+states[0][person.state] console.log(temp) } });
As you can see from the screenshots below – the ajax calls can be executed in either order and still the result stands because the .done() function is not run until both are complete
Conclusion
This is a very interesting capability which has apparently been around for ages and I wish I had known about it earlier (added jQuery v1.5)
…and now I just learned about that as well – thanks!
My pleasure 🙂
…and if you are using angular, it’s $q.all(). For dojo, it’s dojo.all().