As I mentioned previously, one of the most exciting sessions at DevLink was Asynchronous JavaScript. My biggest spark was from seeing an answer to a problem I have faced down many times and the solutions I have come up with always made me die a little bit inside. I hated chaining JS callbacks for the specific purpose of making a secondary Ajax call, especially when the data was unrelated. The answer to this is something that has existing in JQuery for a while now, I actually had heard of it but had not realized the full scope of what it brought to the table.
The idea of a Deferreds is to create a single object which can notify all other callers. This allows you to define handling logic that is executed only after both calls have completed successfully. I decided to craft a very simplistic example of this, just a couple calls to the Twitter Search API, here is the function that does the Ajax call:
function makeTwitterSearchRequest(query) { return $.ajax("http://search.twitter.com/search.json?q=" + query, { async: true, contentType: 'application/json', dataType: 'jsonp', data: {}, type: 'GET', crossDomain: true }); }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
(to make this fit I did omit certain parameters from the Twitter Search Request)
Notice that this code returns the call to $.ajax. This is important. Since JQuery 1.5 the success, error, and complete handlers are being phased out in favor of this new model. You see what this method now return is a “promise” which is a wrapped version of the Deferred ($.Deferred). The reason a promise is called is for the sake of proper encapsulation, wont get into that here. Just understand that the fact it returns a “promise” is why the new pattern is to use the done(), fail(), complete() methods to handle the various outcomes. But this gives us another benefit, we can use the results in conjunction with other methods in the Deferred architecture, like this:
var appleRequest = makeTwitterSearchRequest("apple"); var microsoftRequest = makeTwitterSearchRequest("microsoft"); $.when(appleRequest, microsoftRequest).then(function(apple, microsoft) { var appleResults = apple[0].results; var microsoftResults = microsoft[0].results; }).fail(function() { alert("failure"); });
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
This is the power of this approach and what has me so excited. I make TWO AJAX requests and the handler is NOT called until they both complete. And the handler gives me access to all of the information I would need within the menu. This is effectively synchronizing threads (though JavaScript does not have threads per-se, just one giant ass event loop).
I cannot understate how cool and efficient this is. While JS is not multi-threaded and thus cannot get the ultimate benefit from this approach, it does allow the code to be cleaner, which for the programmer should always be a vitally important goal. I cannot tell you how many times I have run into this scenario where I would love something like this. Cannot wait to use it in production, and to think it was there all this time.