Tag: Javascript

Javascript Promises – Part III – Chaining Promise’s

Javascript Promises – Part III – Chaining Promise’s

In the previous parts, we have learned about Promise and Promise error handling.

In this part, we are going to learning about chaining Promise‘s.

Let’s take a look at the following code:

var dogs = ['dog1', 'dog2', 'dog3', 'dog4', 'dog5', 'dog6'];
function printName (name) {
    return new Promise(function(resolve, reject) {
        console.log('printName: ' + name);
        resolve(name);
    });
}

function displayNames(names) {
    var currentName = names.shift();        // take on name out to process
    if (currentName) {                      // if not end of array
        printName(currentName).then(function(name) {
            console.log('printName succeeded: ' + name);
            displayNames(names);
        }).catch(function(name) {
            console.log('printName failed: ' + name);
            displayNames(names);
        });
        
    }
}

displayNames(dogs);

In the example above, we are trying to print the list of dogs’ names in a consequence order, which means name after name, not at the same time.

As you already know, in Javascript, functions return immediately after it is called, and a moment later, the callback function is called when the job actually finished. This leads to a situation where we can’t do a list of jobs one after another.

Promise give us the power to do just what we want by chaining promises together.
When promises are chained together, the Javascript engine will only call the second promise’s job when the first promise has been either resolved or rejected. That way the promise’s jobs will be executed one after another.

In the example above, we are using recursion to make the code work in consequence. However, using promise, we can make the code simpler and more expandable.
Let’s look at the easy version first:

var dogs = ['dog1', 'dog2', 'dog3', 'dog4', 'dog5', 'dog6'];
function printName (name) {
    return new Promise(function(resolve, reject) {
        console.log('printName: ' + name);
        resolve(name);
    });
}

printName('dog1')
    .then(function(name){
        console.log('printName succeeded: ' + name);
        printName('dog2').then(function(name){
            console.log('printName succeeded: ' + name);
        });
    });

Instead of writing code like this, we can leverage the power of chaining Promise and rewrite the code as below:

var dogs = ['dog1', 'dog2', 'dog3', 'dog4', 'dog5', 'dog6'];
function printName (name) {
    return new Promise(function(resolve, reject) {
        console.log('printName: ' + name);
        resolve(name);
    });
}

printName('dog1')
    .then(function(name){
        console.log('printName succeeded: ' + name);
        return printName('dog2');
    })
    .then(function(name){
        console.log('printName succeeded: ' + name);
    });

By chaining the promises like above, we are able to print dog2 after dog1. The key point is, instead of passing the resolve and reject function to printName('dog2').then(), we can just return the printName('dog2') as a Promise, and the next .then() just do its job in exactly the same manner as if it was passed to printName('dog2').then(). This works because Promise provide us with the chaining syntax to make the code more comprehensive.

Imagine that instead of creating a chain like this p1 -> (p2 -> (p3 -> p4)), we can now create a chain like p1 -> p2 -> p3 -> p4, which functions exactly the same.

But what if we have a lot of dogs? What if the dog list is dynamically generated? We just can’t know what dogs are there to print. So we must work out a way to dynamically make promise’s chain.

Let’s look at the upgraded version:

var dogs = ['dog1', 'dog2', 'dog3', 'dog4', 'dog5', 'dog6'];
function printName (name) {
    return new Promise(function(resolve, reject) {
        console.log('printName: ' + name);
        resolve(name);
    });
}

var sequence = Promise.resolve();

dogs.forEach(function(name) {
    sequence = sequence.then(function() {
        return printName(name);
    }).then(function(name) {
        console.log('printName succeeded: ' + name);
    }).catch(function() {
        console.log('printName failed: ' + name);
    })
})

In the code above, we use a very interesting trick by writing var sequence = Promise.resolve();, which basically creates an empty promise that has been resolved to use as the beginning promise of the chain. After this, we can add the next promise to the chain easily just by using sequence.then()

Another thing that worth mentioning here is that if we use for instead of forEach, be careful because the index variable will not be the same by the time the promise’s resolve function is called as intended when creating Promise chain.
The code should look like this:

var dogs = ['dog1', 'dog2', 'dog3', 'dog4', 'dog5', 'dog6'];
function printName (name) {
    return new Promise(function(resolve, reject) {
        console.log('printName: ' + name);
        resolve(name);
    });
}

var sequence = Promise.resolve();

for (var i = 0; i < dogs.length; i++) {
    (function() {       // define closure to capture i at each step of loop
        var capturedIndex = i;
        sequence = sequence.then(function() {
            return printName(dogs[capturedIndex]);
        }).then(function(name) {
            console.log('printName succeeded: ' + name);
        }).catch(function() {
            console.log('printName failed: ' + name);
        })
    }())    // invoke closure function immediately
}

Creating an array of promises

Instead of chaining promises together, we can also create an array of promises and wait for all the promises to finish by using Promise.all() like this:

function printName (name) {
    return new Promise(function(resolve, reject) {
        console.log('printName: ' + name);
        resolve(name);
    });
}

var promiseArray = [ printName('dog1'), printName('dog2')];

Promise.all(promiseArray).then(function(names){
    console.log(names);
}).catch(function(names){
    console.log(names);
})

Promise.all will wait for all the promises to finish and then call the final resolve function with the list of PromiseValue of resolved promises in array, as well as call final reject function with the list of PromiseValue of rejected promises in array. In other words, if promise array has 5 promises, 3 of which succeeded and 2 of which failed, then the final resolve function will be called with a list of 3 names and the final reject function will be called with a list of 2 names.

Congratulations, you’ve made it!
I hope you understand what promise is and how it works now.

If my explanation doesn’t seem to work for you, you might want to try reading this very good tutorial here.

If you have any thoughts or questions, please share your comment below.

Cheers!

Javascript Promises – Part II – Handling errors

Javascript Promises – Part II – Handling errors

In the previous article, we’ve learned what Promise is and went through some basic use cases of Promise. In this article, we will learn how to handle errors while using Promise.

If you haven’t read part I, I would recommend that you take a look at it here.

If you’ve read part I, you may have wondered when the reject function would be called and how to specify a real reject function to the Promise.

Actually, in the previous part, to make life simple, we’ve ignored the reject function. The full version of .then() should come with 2 parameter: resolve and reject function.

Reject function

To be clearer on this, let’s open our cool console tab in chrome and type the following code

var p1 = new Promise(function(resolve, reject) {
    console.log('1');
    throw 'Uh-oh!';
});

p1;

The console outputs would be like below:

Promise { [[PromiseStatus]]: "rejected", [[PromiseValue]]: "Uh-oh!" }

Ok, something have changed. p1‘s status is now "rejected" and its PromiseValue is now "Uh-oh!".
What happened was that during its execution, p1 met an error (exception) and it cannot be resolved, but was rejected. Thus its status is "rejected" and the exception is saved in the PromiseValue, so that it can be passed to the “reject function” if specified.

Now let’s try to specify the resolve function as we did in the previous part:

var p2 = p1.then(function(val) {
    console.log('2: ' + val);
    return val;
});

p2;

The console outputs would be:

Promise { [[PromiseStatus]]: "rejected", [[PromiseValue]]: "Uh-oh!" }

p2 status is also "rejected" and the PromiseValue is forwarded to p2. More over, we can see that the “resolve function” was not called since there was no console log output.

Let’s change p2 a little bit by adding a “reject function” to .then():

var p2 = p1.then(
    function(val) {
        console.log('resolve 1: ' + val);
        return val;
    },
    function(err) {
        console.log('reject 1: ' + err);
        return err;
    }
);

p2;

The console outputs would now be:

Promise { [[PromiseStatus]]: "resolved", [[PromiseValue]]: "Uh-oh!" }

p2 is now "resolved", the console logs "reject 1: Uh-oh!" and the PromiseValue is "Uh-oh!", which is because we called return err; in the reject function.
In the code above, we pass 2 params to .then(), the first one is the “resolve function” to call when p1 succeeds, the second one is the “reject function” to call when p1 fails. Since p1 is rejected, the reject function is called. There’s no error during execution of p2 so p2 status is resolved.
Now if we run the following code:

var p3 = p2.then(
    function(val) {
        console.log('resolve 2: ' + val);
        return val;
    },
    function(err) {
        console.log('reject 2: ' + err);
        return err;
    }
);

p3;

The console outputs would be as below:

Promise { [[PromiseStatus]]: "resolved", [[PromiseValue]]: "Uh-oh!" }

We can see that the “resolve function” was called and p3 is resolved .

then() and catch()

To make life even simpler and code even clearer, Promise provides us with another helpful function: catch()
Instead of writing this:

var p2 = p1.then(
    function(val) {
        console.log('resolve 1: ' + val);
        return val;
    },
    function(err) {
        console.log('reject 1: ' + err);
        return err;
    }
);

p2;

We can now write this:

var p2 = p1
    .then(function(val) {
        console.log('resolve 1: ' + val);
        return val;
    })
    .catch(function(err) {
         console.log('reject 1: ' + err);
         return err;
    })

p2;

Which will basically execute and output the same thing:

Promise { [[PromiseStatus]]: "resolved", [[PromiseValue]]: "Uh-oh!" }

Technically, the call to .catch(rejectFunction) is equal to calling .then(undefined, rejectFunction) and in the the above code, there was actually another Promise in between, right after the first .then(). So the above code is actually:

var p1_1 = p1
    .then(function(val) {
        console.log('resolve 1: ' + val);
        return val;
    });

p1_1;

var p2 = p1_1.catch(function(err) {
    console.log('reject 1: ' + err);
    return err;
})

p2;

One good thing about Promise is that if an error is not handled by a promise, it make the promise rejected and keep forwarding the error to the next promise. Therefore in the above code, p1 does not have a reject function so p1_1‘s status is rejected and the error get passed to the next promise. Since p1_1 has a reject function (specified by .catch()), p2 is resolved.

If we don’t use .catch(), and specified the reject function inside of a .then(), then we must specified the next nested layer of resolve and reject functions inside of the first reject function, and if this keeps going on, we would end up in the same callback hell as when we don’t use Promise at all.

By using .catch(), the error handling would also be much simpler when we chain promise after promise like this:

var p2 = p1
    .then(resolveFunc1)
    .then(resolveFunc2)
    .then(resolveFunc3)
    .then(resolveFunc4)
    .catch(rejectFunc);

When we write like this, if error happens during any node of the promise chain, the rejectFunc will be called.
We can also catch the error for a particular promise separately like this:

var p2 = p1
    .then(resolveFunc1)
    .then(resolveFunc2)
    .catch(rejectFunc2)
    .then(resolveFunc3)
    .then(resolveFunc4)
    .catch(rejectFunc);

In this part, you’ve learned how to handle errors using reject function and .catch(). We will discuss more on Promise chain in the next part of this blog series. That’s it for part II.

Next in series: Javascript Promises – Part III – Chaining Promise’s

Javascript Promises – Part I – Getting started

Javascript Promises – Part I – Getting started

Have you ever seen those javascript codes that keep adding .then() and .then() all over the place and you wonder what the hell is happenning? You are not alone my friend. Today I’m going to talk about these things called Promise and tell you what, after you understand this Promise thing, you’ll find it one of the coolest thing Javascript has ever made.

Who should read this article?

This article applies to both javascript on the browser and javascript in Node.JS. So anyone who uses either of those may find this article helpful.

Why Promise?

Back in history, Javascript is all about callbacks. When we tell the code to do some task, we don’t wait for it to finish, but instead, we pass a callback to it so that the code can call the callback when the task is done.
Now if you want the callback above to do another task and then do something with the result from this second task, you add another callback to the previous callback. And when this adds up, you may get 10 layers of callback in your code and now you can’t even understand your own code flow. This situation is usually referred to as “callback hell”.

Getting started

Ok, let’s get down to business. At the heart of JavaScript Promise is the Promise constructor function, which looks like this:

var mypromise = new Promise(function(resolve, reject){
    // asynchronous code to run here
    // call resolve() to indicate task successfully completed
    // call reject() to indicate task has failed 
});

We can think of it this way: each Promise has a “main” function, which is the code that actually does the job. This “main” function takes two parameters including a resolve function – which main will call when the job is successfully done; and a reject function – which main will call if there is any error while executing the job.

Let’s see the whole thing in action to better understand it.

Introduction to Promise

This is how a code with Promise might look like:

function getImage(url){
    return new Promise(function(resolve, reject){
        var img = new Image()
        img.onload = function(){
            resolve(url);
        };
        img.onerror = function(){
            reject(url);
        };
        img.src = url;
    });
}

What just happened? We’ve just created a function which returns a Promise. The Promise loads an image; and then if the loading succeeds, calls resolve with url as parameter and if failed, calls reject, also with url as parameter.

It’s normal if you don’t get the idea up until now. We’ll try to explain more in details in the several next paragraphs.

Now we can call this function like below:

getImage('doggy.jpg').then(function(successurl){
    console.log('successfully loaded: ' + successurl);
});

Let’s first understand what’ve just happenned.
After getImage return a Promise, we provide that Promise with a resolve function. The Javascript engine will then pass the url to the resolve function as stated in the main function of the Promise:

img.onload = function(){
    resolve(url);
};

Now that we have rough idea of what a Promise looks like, let’s take a look at a simpler example.

The easiest way to get a visualization on this is by opening a Google Chrome browser and open Developer Tools panel (usually by pressing F12 on Windows, or Command-Alt-I on Mac, or from the Menu -> More tools -> Developer tools). Navigate to console tab and let’s do the business.

Ok you don’t need incognito mode. I just open incognito mode out of habit, if you know what I mean ;))

Creating your first Promise

Paste this in your chrome’s console:

var p1 = new Promise(function(resolve, reject) {
    console.log('1');
    return 'value 1';
});

p1;

We’ve just create a Promise named p1 and then print it to console to see its status, which results in something like this in the console:

Promise { [[PromiseStatus]]: "pending", [[PromiseValue]]: undefined }

So p1‘s status is pending, and no PromiseValue is returned yet. That is because we haven’t called resolve nor reject while executing the main function
Let’s change p1 a little bit

var p1 = new Promise(function(resolve, reject) {
    console.log('1');
    resolve('value 1');
});

p1;

Notice that this time we’ve changed return 'value 1'; in the previous code block to resolve('value 1');. The console now returns with:

Promise { [[PromiseStatus]]: "resolved", [[PromiseValue]]: "value 1" }

Yay! The promise is now resolved, and PromiseValue is now "value 1".
Now let’s type this into your console:

var p2 = p1.then(function(val) {
    console.log('2: ' + val);
    return val;
});

p2;

The console returns with:

Promise { [[PromiseStatus]]: "resolved", [[PromiseValue]]: "value 1" }

What just happened? By calling p1.then, we specify the resolve function for p1. So now when the main function of p1 compeletes, it knows which resolve function to call. So now it call the function specified in then(), and pass p1.PromiseValue to that function as param (in this case val).

But wait, p1 already finished before the real resolve function was passed to p1.then. How did that resolve function be called?

So, Promise is a mechanism provided by javascript engine, and Javascript Engine is the one who called that resolve function. Let’s imagine that Javascript Engine has a timer that continuously check the status of Promise p1. When p1 finishes, it updates the p1.status to either resolved or rejected, and save the <PromiseValue so that it will use to pass to resolve or reject function later on. Then it checks if a real resolve function is specified. If no resolve function is specified, it just leave the Promise there and recheck in its next timer loop. Half an hour later, someone specifies the real resolve function for p1 by calling p1.then(resolveFunc). In its next timer loop, Javascript Engine finds out that p1 now has a real resolve function so Javascript Engine calls that function with p1.PromiseValue as the function’s first parameter.

Another fancy thing to notice in the previous example is that p2 is also a Promise. Technically, to return a Promise, that block of code should be rewritten as below:

var p2 = p1.then(function(val) {
    console.log('2: ' + val);
    return new Promise(function (resolve, reject) {
        resolve(val);
    })
});

By default, Promise.then() returns a Promise. But Promise.then() is smart enough to check if the passed in function returns a value, it will wrap that function into a Promise and the returned value of that function will be the PromiseValue. On the other hand, if the passed in function returns a Promise, Promise.then() will just forward that Promise as its returned object.

Therefore, in the previous block of code, when .then() finds out that the passed in function just return val; it wrap that function into a Promise and return the Promise instead. Later, when that function finishes, it knows that it would use the value returned from the function to assign to PromiseValue of the returned Promise (p2).

Now that p2 is a Promise, we can continue to use then() on it as below:

var p3 = p2.then(function(val) {
    console.log('3: ' + val);
    return val;
});

p3;

The console output should be like this:

Promise { [[PromiseStatus]]: "resolved", [[PromiseValue]]: "value 1" }

which means p3 is also a Promise, it has been resolved and its PromiseValue is "value 1", waiting to be passed on to the next Promise if there is any.

Ok that’s it for part I. Now you know what Promise is and what those .then() functions mean.

In the next parts, we will look more into error handling in Promise and how Promise‘s are chained.

Next in series: Javascript Promises – Part II – Handling errors