Promises in JavaScript

Understand Promises in JavaScript


You know that moment you promise to send your friends a Christmas gift and they have to wait for you to keep that promise(resolve), then further actions can be taken or if you break the promise(reject), they would like to know what happened (catch), so that they can plan what to do next or how to handle it. Well, let me introduce you to Promises in JavaScript.

Promises in JavaScript

Promises represent the final completion or failure of an asynchronous operation and its resulting value. Promises are initialized with an executor function as an argument. The executor function must contain two arguments resolve and reject and would be called immediately by the Promise implementation.

let myPromise = new Promise(/* executor function goes here */);

Resolving Promises

In the executor function, we tell it what we want it to do. Let’s modify the snippet above to see what it actually looks like.

let myPromise = new Promise((resolve, reject) => {
  // let's do something here
  setTimeout(async () => {
    resolve( 2 + 2); // we are resolving our promise
  }, 3000);
});
myPromise.then(result => {
  console.log(result); // 4 
});

In our executor function, we assume that we performed several operations and it took some time to resolve it. But in our case, we decided to use the setTimeout() function to cause a delay before resolving it. Then we take our promise that has been fulfilled and log it on the console. It is simple right?

Promise.then()

The Promise.then() returns a new promise when called, and executes an operation on the promise using onFulfilled and onRejected as they will run if the promise gets fulfilled or rejected. 

The resultCapability can also be passed as an optional, the result is stored by updating resultCapability’s promise. (If it is not passed, the promise is being called by an internal operation where the result does not matter.) The example above also shows the resultCapability being passed. Let use rewrite our code to show the onFulfilled and onRejected. Add this snippet below our previous Promise.then().

function resolved(result) {
  //Do something
  console.log("Our promise got resolved");
}
function rejected(result) {
  console.log("Our Promise was rejected");
}

myPromise.then(resolved, rejected); // "Our promise got resolved"

This allows us to have custom callbacks that will execute if our promise gets fulfilled or rejected.

Chaining Promises

Assume that you have lots of things to wait for before fulfilling your promise of sending gifts to your friends. Example of those could be that you ordered something form an online store and you have to wait for it to arrive, after it has arrived you decided to sell it so that you could get something better, before finally sending the gifts to your friends.

let chainedPromise = new Promise((resolve, reject) => {
    let orderedItem = "Home Assistant";
    setTimeout(orderedItem => {
        resolve(orderedItem);
    }, 3000, orderedItem);
});

chainedPromise.then(result => {
    console.log(`Your ${result} has arrived`);
        return new Promise((resolve, reject) => {
            console.log("Selling Item");
            resolve("Item has been sold");
        });
}).then(result => {
    console.log(result);
    return new Promise((resolve, reject) => {
        let buyingGifts = true;
        if(buyingGifts == true){
            resolve("Bought the gifts");
        }else{
            reject("Couldn't buy the gifts");
        }
    });
}).then(result => {
    console.log(result);
    return new Promise((resolve, reject) => {
        resolve("Sent the gifts to your friends");
    });
}).then(result => {
    console.log(result);
}).catch(result => {
    console.log("Failed to keep promise");
});

This will log the following in the console.

// "Your Home Assistant has arrived"
// "Selling Item"
// "Item has been sold"
// "Bought the gifts"
// "Sent the gifts to your friends"

Failing Promises

We should dive in a little bit more. What happens if our Promise gets rejected? or should I ask, what do you think will happen if we fail to keep our promise?. Yeah… I know what you are thinking, we need to offer an explanation right?. Let’s create an oldPromise we failed to keep and see how it works in code.

let truthyValue = false;
let myOldPromise = new Promise((resolve, reject) => {
  setTimeout((truthyValue) => {
    //lets do something here
  }, 3000, truthyValue);
});

In our setTimout() function let’s add a conditional statement to check our truthy value.

if(truthyValue){
  resolve(2 + 2);
}else{
  reject("Our truthy value was false");
}

Now.. Let us catch our error. Using the catch() method, we can capture errors that occur if our promise failed to resolve.

myOldPromise.catch((result) => {
  console.log(result); // "Our truthy value was false"
});

Promise APIs

There are five static methods in the Promise class, we will talk briefly on them.

Promise.resolve()

Promise.resolve() is creates a resolved promise with any argument passed as it as it’s result.

Promise.resolve(anyValue); // resolves promise with anyValue as result

This is the same as:

let newPromise = new Promise(resolve => resolve(anything));

Promise.reject()

Promise.resolve() is creates a resolved promise with any argument passed as it as it’s result.

Promise.resolve(anyValue); //resolves promise with anyValue as result

This is also the same as:

let newPromise = new Promise(reject => reject(anything));

Promise.all()

Let’s say we want to run many promises to execute in parallel, and wait until all of them are ready.

The method returns a new promise which fulfills when all of the promises passed as an iterable have been fulfilled or when the iterable contains no promises and rejects with the reason of the first promise to reject. The syntax is quite simple.

Promise.all([promise1, promise2, promise3]).then(/* Do something */);

Promise.allSettled()

It waits for all the promises that were passed in as arguments to get settled (To either get fulfilled or rejected), then returns a new Promise with an array of objects that each describes the outcome of each promise.

let promise1 = new Promise((resolve, reject) => setTimeout(resolve, 900, 'good'));
let promise2 = Promise.reject("bad");

Promise.allSettled([promise1, promise2]).
  then((results) => console.log(results));

// logs an array of objects to the console
/* 
[
  { status: "fulfilled", value: "good" },
  { status: "rejected", reason: "bad" }
] 
*/

Promise.race()

This method returns a promise with the result/error of the first fulfilled or rejected promise.

let promise1 = new Promise((resolve, reject) => {
    setTimeout(resolve, 500, 'firstPromise');
});

let promise2 = new Promise((resolve, reject) => {
    setTimeout(reject, 1000, 'secondPromise');
});

Promise.race([promise1, promise2]).then((result) {
  console.log(result); // 'firstPromise'
});

Conclusion

Promises are a very good way of handling asynchronous operations in JavaScript and they are easy to use. Of all the static methods in the Promise class, Promise.all() is the most commonly used. I hope you learned a few things, if you have any questions or suggestions please leave it in the comment section below.


Share on social media

//