Once upon a time there was XMLHttpRequest. It was firstly invented by Microsoft, but very quickly became popular and other big companies like Google and Mozilla also adopted it. Now it is a W3C standard and all (relatively new) browsers support it. The idea behind XMLHttpRequest is to do a request to a server without doing a full page load. This can enable small portions of the HTML page to be updated dynamically and lead to better user experience. Furthermore, the term AJAX appeared, which stands for Asynchronous JavaScript and XML (note, there are some discussions whether the X stands for XML or XMLHttpRequest, but this is outside the scope of this post). Although AJAX was initially meant for XML communication, it can be used for other data types, f.x. JSON). This is how a developer can make a request to the server:
1 2 3 4 5 6 |
var r = new XMLHttpRequest(); r.onload = function() { alert(this.responseText); }; r.open("get", "http://mywebsite.com/myresource.php", true); r.send(); |
Developers started using XMLHttpRequest more and more and as they tend to make their life easier, they started creating different abstractions over it. Moreover, the client-side logic became more complex, which involved a more sophisticated communication with the server. One such abstraction is jQuery. Besides introducing a much easier way to work with DOM operations, jQuery also introduced a new way of using XMLHttpRequest.
1 2 3 4 5 |
$.ajax({ url: "/myresource.php", success: function(result) { }, error: function(err) { } }); |
The rise of the promises
By attaching callbacks, developers can handle different scenarios more easily. But then the necessity of attaching multiple callbacks appeared. For example. a developer is interested in passing the XMLHttpRequest to a range of methods where each method attaches its own success callback. To address this issue, since jQuery 1.5 the $.ajax method returns an implementation of the CommonJS Promises/A interface. By using this interface, the example from above can be rewritten to the following:
1 2 |
$.ajax({ url: '/myresource.php' }) .done(function(result) { }).fail(function() { }); |
But what is actually a promise? Technically seen it is an interface with a couple of methods (f.x. done, fail). Theoretically seen it gives us the promise that something will happen in the future – either we will get an error or everything will run normally. Thus, we can attach our callbacks to handle these cases.
So instead of setting the callbacks as parameters to the $.ajax method, we can attach them later. And we can attach many of them. And we can do it even after the response from the server is received. By using the promise interface we can for example implement the pipe & filters pattern in a very clean way. Another advantage is the possibility to combine promises. By using the $.when method that jQuery provides, one gets a new promise, which will be “successful” only if all the promises are successful.
1 2 |
$.when(promise1, promise2) .done(function() { }).done(function() { }) |
Another methods that jQuery provides in the context of promises are:
- .then(successFn, failFn, progressFn) = .done(successFn).fail(failFn).progress(progressFn)
This method returns a new promise, so you can actually change the output of the initial promise. - .always(fn) = .done(fn).fail(fn)
Creating own promises
It can happen that in our own code we have to perform some time-consuming activities. Note that such activities should be performed with care, as they may block the UI thread and hang the browser of the user. jQuery provides an implementation of the promise interface that we can manipulate – deferred objects. The following example demonstrate the usage of a deferred object.
1 2 3 4 5 6 7 8 9 10 |
function myPromise() { var d = $.Deferred(); setTimeout(function() { if ((new Date()).getTime() % 2 === 0) d.resolve(); else d.reject(); }, 1000); return d.promise(); } myPromise().done(function() { }).fail(function() { }); |
Tadaam! Now we can benefit from the advantages of promises in jQuery in our client-side applications. There are of course also other libraries that provide implementations of the promise interface. However, the principles are similar.
Further reading
- You’re Missing the Point of Promises
- Q – a library that implements Promises/A