Chaining

Chaining is what is so great about promises.

Since Promises capture the notion of asynchronicity in an object, we can chain them, map them, have them run in parallel or sequential, all kinds of useful things. Code like the following is very common with Promises:

getSomeData()
.then(filterTheData)
.then(processTheData)
.then(displayTheData);

getSomeData is returning a Promise, as evidenced by the call to then(), but the result of that first then must also be a Promise, as we call then() again (and yet again!) That’s exactly what happens, if we can convince then() to return a Promise, things get more interesting.

then() always returns a Promise

then() takes 2 arguments, one for success, one for failure (or fulfill and reject, in promises-speak), each will return a promises.

Transforming values

Chaining promises is useful for transforming values, each .then(func) return a promise resolved with the returned value of func. For example:

var promise = new Promise(function(resolve, reject) {
    resolve(1);
});

promise
.then(function(val) {
    console.log(val); // 1
    return val + 2;
})
.then(function(val) {
    console.log(val); // 3
    return val * 3;
});
.then(function(val) {
    console.log(val); // 9
});

As a practical example, chaining of promises is great for processing data from an HTTP request: get the content - parse the content - filter the content.

Example with the GitHub API

Here is an example using the GitHub API and promises, that will display the list of repositories of the most followed GitHub user.

For this example, we'll consider the method get(url) as doing the HTTP GET method to url and returning a promise that'll be resolved with the plain text content.

var BASE_URL = "https://api.github.com";

function getReposMostFollowedUser() {
    // Serach users and ordr by followers
    return get(BASE_URL + "/search/users?q=followers:>500&sort=followers&order=desc")

    // Parse the text content as JSON
    .then(JSON.parse)

    // Extract first user
    .then(function(users) {
        if (users.length == 0) throw "No user to return";

        return users[0];
    })

    // Get repositories list for the user
    .then(function(user) {
        return get(BASE_URL + "/users/"+user.login+"/repos")
    })

    // Parse the text content as JSON
    .then(JSON.parse);    
};

Then we can easily call the method getReposMostFollowedUser() that will return a promise.

getReposMostFollowedUser()
.then(function(repos) {
    console.log("Repos:", repos);
});

Last updated