Nicholas M. Salvatore

Back arrow

Understanding Javascript Promises

What is a promise?

A promise is an object that returns a "promise" that it will return with either a resolved value or a rejection. Regardless of what is returned, the "promise" being made is that a conclusive response will in fact take place. That response may just take a moment to be fulfilled.

Basic anatomy of a promise

Using the promise constructor, a promise can be created to give a general overview of how promises work. In the following example, I've created a promise to say hello in 3 seconds in the form of a sayHello() function.

const sayHello = new Promise((resolve, reject) => {
    const personIsNice = true;
    
    setTimeout(() => {
        return personIsNice ? resolve('hello') : reject('uh oh!');
    }, 3000);
});

sayHello
    .then(value => {
        console.log(value);
    });
    .catch(error => {
        console.log('Unable to say hello');
        throw new Error(error);
    });

As you can see, the promise constructor has a single executor parameter that takes two functions as parameters: resolve and reject. You can then use .then() to perform an operation with the resolved value or use .catch() to do something with the rejected value, as is shown above.

To walk through the example, the promise is first created with new Promise syntax. If personIsNice is set to true, the promise will resolve with a value of "hello" and if personIsNice is set to false, the promise will reject with a value of "uh oh!" To imitate the delay it might take while a promise is pending, the logic for determining the completed state is wrapped in a setTimeout function that waits 3 seconds to perform this calculation. The .then() method is then applied to sayHello value argument in .then() will be the result of sayHello if the promise does in fact resolve. If the promise is rejected, .catch()will catch the error and you can do what you wish with that error. In the case of the code above, since personIsNice is true, "hello" will be logged after a 3 second delay.

Async/await

The above code block can also be written using async and await syntax.

const sayHello = new Promise((resolve, reject) => {
    const personIsNice = true;
    
    setTimeout(() => {
        return personIsNice ? resolve('hello') : reject('uh oh!');
    }, 3000);
});

(async () => {
    try {
        const hello = await sayHello;
        console.log(hello);
    } catch (error) {
        console.error('Unable to say hello');
        throw new Error(error);
    }
})();

Instead of using .then() to get the value of the resolved promise, we can wrap the logic for dealing with our resolved value in a try block and use await to pass the value directly to a variable, in this case hello, which is then logged. To access the possible rejected state of our promise, we a catch block where the error argument will be the rejected value of the promise. And since await cannot be used outside of a function with an async declaration, the logic to deal with our sayHello promise is wrapped in an immediately invoked function expression (IIFE) that has been declared as asynchronous.

I don't think I ever realized that .then() and .catch() actually feels like cleaner syntax in some cases, such as the above case.