A Brief Introduction to Promises

Falafel Software Bloggers
Falafel Software
Published in
3 min readNov 29, 2016

It took me a while to get used to working with Promises in JavaScript. I fundamentally knew how the jQuery Deferred object worked from years ago, so some of the concepts were familiar to me. But, the beauty of the newer Promise implementations is in how it really cleans up your code by breaking it up into blocks that can then be chained and executed asynchronously.

Consider the following:

function fetchSomething() {
return someHttpClient.get(someUrl);
}

function doSomething() {
return fetchSomething()
.then(function(res) {
return res.data.length;
});
}

doSomething()
.then(function(len) {
console.log(len);
})
.catch(function(err) {
console.error(err);
});

The process is kicked off at the bottom with a call to doSomething() . Notice that doSomething() calls fetchSomething() , and all that fetchSomething() does is return the results of someHttpClient.get() . But, in this case, suppose that the implementation of get() returns a Promise, not a value. So, when fetchSomething() runs, it returns nearly immediately, while the underlying HTTP GET operation that is being performed may take many seconds to actually execute.

The Promise is what allows that long-running GET operation to take place asynchronously. That is, the doSomething() code is not blocked waiting for the web request to finish running. But, in this case, doSomething() is also returning the result of fetchSomething() , which is a Promise, so it finishes executing nearly immediately, too, and doesn’t block the original calling code.

Eventually, that web request will complete and an actual value will exist. This is when the Promise is resolved. Everything that was waiting for the value from the get() operation will receive it via chained then() functions. The first then() in the chain above is in the doSomething() function, which receives the response value from the Promise, and then returns a totally different value.

Now, I said above that doSomething() returns the result of fetchSomething() , but in reality, it returns the result of calling the chained then() function on the Promise returned from fetchSomething() , which is itself a Promise (“turtles all the way down” comes to mind here). So, the callback function defined in the then() is not executed until the Promise is resolved, which in this case, is not until the web request finishes.

The then() inside the doSomething() function resolves its Promise by returning the length of the data received from the web request. So, the then() chained to the doSomething() call at the bottom will not receive the original response value from the get() Promise, but rather, will receive a numeric value instead.

What about error handling? The way that my preferred Promise library (Bluebird.js) does this is with a special catch() convenience method. It works like then() chaining, but for errors only (i.e., when Promises are rejected as opposed to resolved). In the code above, there is only one catch() defined, so an error anywhere in the Promise chain will bubble up to be handled in one place.

Without Promises, the logic above would resemble the following synchronous code, which blocks execution each step along the way:

function fetchSomething() {
return someHttpClient.get(someUrl);
}

function doSomething() {
var res = fetchSomething();
return res.data.length;
}

try {
var len = doSomething();
console.log(len);
}
catch (err) {
console.error(err);
};

Originally published at Falafel Software Blog.

--

--