Deferred for Javascript (Prototype)
Continuing the Deferred theme for JavaScript, I suggest another rewriting of Deferred, now in Prototype terms . You can read more about Deferred itself in two of my past notes: Asynchronous programming: the Deferred concept and Deferred: all the details . In short, the most common and useful application of Deferred in JavaScript is working with AJAX or other RPC-over-HTTP calls, when you need to make a chain of logically connected calls, correctly handle errors that occur, etc. In my opinion, Deferred is essential in such situations.
Let's move on to the examples: accessing some JSON-RPC API based on Prototype's Ajax.Request can be wrapped in Deferred as follows:
var Api = Class.create({
initialize: function(url)
{
this.url = url;
},
call: function(method, params)
{
var requestBody = $H({ 'method' : method, 'params' : params }).toJSON();
var d = new Deferred();
var onSuccess = function(transport)
{
result = transport.responseText.evalJSON();
if ('faultCode' in result && 'faultString' in result)
{
var err = new Error(result.faultString);
err.faultCode = result.faultCode;
err.faultString = result.faultString;
d.errback(err);
}
else
{
result = result[0];
console.log("Got result: ", result);
d.callback(result);
}
};
var onFailure = function(transport)
{
d.errback(new Error("API transport error: " + transport.status))
};
var onException = function(error)
{
d.errback(error);
}
new Ajax.Request(this.url, {
method: 'post',
postBody: requestBody,
requestHeaders: { 'Content-Type' : 'application/json' },
onSuccess: onSuccess,
onFailure: onFailure,
onException: onException,
});
return d;
},
});
Here, any call to
Api.call
will be returned by a new Deferred, which will contain the result of a remote call or exception (transport or from the server we are accessing). Let there be RPC calls sum
and mult
, which, respectively, add and multiply their arguments. Then evaluating the expression (2+3)*7
using our class Api
will look like this: var api = new Api;
api.call('sum', [2, 3])
.addCallback(
function (sum_of_2_and_3)
{
return api.call('mult', [sum_of_2_and_3, 7]);
})
.addCallback(
function(result)
{
alert('(2+3)*7 = ' + result);
})
.addErrback(
function (error)
{
alert('Mmm… something wrong happened: ' + error);
});
Well and most importantly:
- source code Deferred.js ;
- MIT license, like the very first Deferred version for JavaScript .