The Blackninja Blog
Expand your Cloud Application Development and DevOps knowledge with detailed tutorials and case studies.
When you dive into client side development, one of the first challenges you’ll encounter is asynchronous vs. synchronous function calls.
When you make a synchronous call, it executes the code you declared and doesn’t return until its done. It runs the code, waits, and then returns.
When you make an asynchronous call, it executes the code you declared and carries on immediately! Then at some point in the future it returns.
This is challenging because rarely do we need to fire off a call and forget. Quite often we need to act on the result of that execution. So we need to wait and then do something.
The answer is promises. Promises are simply a programming paradigm that deals with the challenges of asynchronous calls. It does this by deferring the execution of some work until something else has finished.
Like it promised. Get it?
Here’s a simple example:
var p = doWork();
p.done(function(result) {
doSomeOtherWork();
});
In this example, doWork returns a promise. I’ve named the variable p
as its become somewhat of a convention, the way i
is often used in a for loop for the index. A promise is simply an object with callback functions that will be executed when the promise is complete.
In this example I am only using the done callback. There is also a fail callback for when the promise isn’t completed, or in promise terminology: it isn’t fulfilled.
In order to return a promise, you need to create an object called a Deferred. Its very simple, and it gives you access to a promise:
function doWork() {
var d = $.Deferred();
// some asynchronous task like call an api...
return d.promise();
}
In this example I am creating a jQuery Deferred and then calling its promise() method to return a promise object. Remember, a promise is simply an object with some callbacks: done and fail. So how do we tell the outside world that our promise has been fulfilled?
We call another function on our Deferred. Resolve.
function successCallback(d) {
d.resolve();
}
In this example, I have some callback that will be executed by my promise when it successfully completes. I need to make sure that function gets passed my deferred object that I created and then simply call the resolve() method on it.
function failCallback(d) {
d.reject();
}
This example is very much like the previous one, but I’m simply calling reject instead of resolve(). This means the consumer of my promise will need to also handle the fail() callback as well as the done().
So how does this all work together?
function successCallback(result) {
this.d.resolve(result);
}
function failCallback() {
this.d.reject("something bad happened");
}
function makeAsyncCall(url) {
var d = $.Deferred();
$.ajax({
url: url,
success: successCallback,
error: failCallback
})
return d.promise();
}
var p = makeAsyncCall(url);
p.done(function(result) {
// result what we passed to resolve()!
// do something with the result
});
p.fail(function(result) {
// result is a string because that is what we passed to reject()!
var error = result;
console.log(error);
});
The makeAsyncCall() function makes an asynchronous call and returns a promise because the code is not going to return right away. The promise isn’t resolved or rejected until that asynchronous code returns.
So you can now see how using jQuery Deferred’s and Promises can help manage working with asynchronous function calls. You can create other functions that wouldn’t be invoked until makeAsyncCall() was resolved by calling them inside the done() callback. Those could also return their own promises in order to manage the asynchronous nature of javascript development.
Now go make some promises!