Welcome, Guest: Register On Nairaland / LOGIN! / Trending / Recent / New
Stats: 3,152,735 members, 7,817,019 topics. Date: Friday, 03 May 2024 at 11:11 PM

Deferred / Promise Explained (javascript) - Programming - Nairaland

Nairaland Forum / Science/Technology / Programming / Deferred / Promise Explained (javascript) (2499 Views)

Were Can I Download Free Video Tutorials On Javascript Or Ruby / Javascript With NodeJS / The Java Virtual Machine Explained (2) (3) (4)

(1) (Reply)

Deferred / Promise Explained (javascript) by kadeerna: 1:11am On Jul 22, 2012
jQuery 1.5 saw a rewrite of $.ajax introducing Promises (sometimes called Deferreds) providing amongst other benefits, a cleaner way of managing callbacks on success/failure. Prior to the rewrite, the implementation of $.ajax made scenarios like the following a mess. Making multiple AJAX requests in which the parameters of a request depended on the sucess and return value of the request before (nested callbacks). There was not a simple way to pass multiple callbacks to be called on success or failure of the request. Hacks like creating an array of functions to be called, creating a function that called the functions in the array, checking return values, and other operations made application code unclean and unmanageable polluting biz logic and bloating LOC unecessarily. Lets see some code to handle multiple callbacks on success or error of a request.

Example:


var CallbackManager = function() {
return {
callbackList: [],

callCallbacks: function(data) {
for (var i = 0; i < this.callbackList.length; i++) {
if (typeof this.callbackList[i] == "function"wink {
// check for uniqueness using a === if this was a unique callback list
this.callbackList[i](data);
}
}
},

addCallback: function(func) {
this.callbackList.push(func);
// to make chainable
return this;
}
}
}

successCallbacksManager = new CallbackManager()
successCallbacksManager
.addCallback(function() { console.log("Callback 1: Call me first"wink })
.addCallback(function() { console.log("Callback 2: Call me next"wink });

errorCallbacksManager = new CallbackManager()
errorCallbacksManager
.addCallback(function() { console.error("Callback 1: An error occured"wink })

$.ajax ({
url: "example.com/createanexample",
data: {
param1: "kadeerna"
}
}, successCallbacksManager.callCallbacks, errorCallbacksManager.callCallbacks)


Developers saw a common pattern in recurring uses of methods like the above and factored out a proposal called the Promises/A proposal. The dojo library V0.9 was one of the first libraries to ship with a Promise/A implementation. The reasons I gave above are only some of the higher level reasons for factoring a common spec. Several lower level reasons exist. Check out the web for more on the Promise/A.

In the example listing above, all callbacks for error and success had to be registered before initiating the AJAX request. The promise pattern allowed code to be written to say perform this/these set of operations (asynchronously), and call on me when you where done. The called code said, aight, take this promise from me that I would do just that. The promise pattern takes the concept further to say, if you ask me call more callbacks later, way way later after I have done and completed (or failed) the async operation, I will call the newly registered callbacks too. Tweaks can be made to call all registered callbacks all again when a new callback is added to the list, or just as described call only the newly registered callback. It is that promise that makes the following code possible using jquery > v1.5.


(What is the world turning into eh? Computers can drive, think, speak, and now promise? Well, fear not. The kill switch is not far.)


var xhr = $.ajax({

url: "example.com/createanexample",
data: {
param1: "kadeerna"
}

});

xhr.done(function() { console.log("Callback 1: Call me first"wink })
.done(function() { console.log("Callback 2: Call me next"wink });

xhr.error(function() { console.error("Callback 1: An error occured"wink })

// add a callback 5 seconds later even when this AJAX request might been done and returned
setTimeout(function() {
xhr.done(function() { console.log("Callback 3: Call me last"wink })
});


So this doesn't seem too juju'ish, lemme explain in code a bit of what happens inside of $.ajax. When $.ajax is called, it returns an xhr object that implements the Promise API. Actually, let's forget about the XHR API for now, and focus on the promise API. The promise API and object might look like the following.


var Promise = function() {
return {
// bad design, only for simplicity
resolved: false,
data: null,

callbackManager: new CallbackManager(),
resolve: function(data) {
this.data = data;
this.callbackManager.callCallbacks(data);
this.resolved = true;
},
done: function(callback) {
this.callbackManager.addCallback(callback);
if (!this.resolved) {
return;
} else {
callback(this.data)
}
}
}
}

var $.ajax = function(options) {
// no checking done here
var url = options.url;
var data = options.data;
var promise = new Promise();

xhr = ...
// create XMLHttpRequest object,
// pass options,

xhr.onload = function() {
if (this.status == 200) {
// parse the result
data = JSON.parse(this.responseText);
promise.resolve(data);
}
}

xhr.send();

// this call is immediate
return promise;
}


If the above listing seemed complicated, imagine that was the following


var APromise = function() {
var promise = new Promise();

// assume this is the async op. this one takes 5 seconds to complete
setTimeout(function() {
promise.resolve()
}, 5000)

// this runs immediately, even before the above LOC
console.log("This is proof."wink

return promise;
};

var ap = new APromise();

ap.done(function() { console.log("Promises"wink });

// add another call back 8 seconds later
setTimeout(function() { ap.done(function() { console.log("Promises"wink }); }, 8000);


A promise object holds a list of callbacks to be called. When the operation that returns that promise resolves (completes or fails), it asks the promise to fulfill itself by calling the Promise.resolve() function. Promise.resolve goes on ahead and calls all registered callbacks registered through the Promise.done(function).

The various Promise pattern implementations improve upon the described method to provide powerful callback mechanisms that allow biz logic to be focused upon. An example is $.when + $.then in jQuery which allows you combine multiple deferred objects and wait for all of the to resolve before calling a callback.


// ...

var ajaxToDebitAccount = $.ajax ...
var ajaxToCreditAccount = $.ajax ...

$.when(ajaxToDebitAccount, ajaxToCreditAccount).then(function(statusDebit, statusCredit) {
if (statusDebit.success && statusCredit.success) {
console.log("Transfer successfull."wink
}
});

// ...


I hope I have been able to explain the concept of Promise / Deferred and you have a better understanding of why you or jQuery makes you use it in your code.
Re: Deferred / Promise Explained (javascript) by Nobody: 10:51am On Jul 22, 2012
to be frank it's a bit complicated here for first time users, although i switch all my AjaX calls to Promises,because its a lot easier to write and far understandable,same concept here also goes for Dojo except we have a when Object that takes a Promise. nice work bro. keep it up this is some quality stuff

(1) (Reply)

Python Programmers Hang-out / 30 Days Of Code {April 19 - May 18} / Got A Remote EU Job But…

(Go Up)

Sections: politics (1) business autos (1) jobs (1) career education (1) romance computers phones travel sports fashion health
religion celebs tv-movies music-radio literature webmasters programming techmarket

Links: (1) (2) (3) (4) (5) (6) (7) (8) (9) (10)

Nairaland - Copyright © 2005 - 2024 Oluwaseun Osewa. All rights reserved. See How To Advertise. 21
Disclaimer: Every Nairaland member is solely responsible for anything that he/she posts or uploads on Nairaland.