Categories
Modern JavaScript

Best of Modern JavaScript — Composing Promises

Spread the love

Since 2015, JavaScript has improved immensely.

It’s much more pleasant to use it now than ever.

In this article, we’ll look at handling JavaScript promise exceptions.

Handling Exceptions in Promise-Based Functions

We can handle exceptions in promise-based functions.

If exceptions are thrown in then and catch callbacks, then the methods convert them into rejections.

However, if we run the synchronous code before the promise code, then the whole function throws an exception.

This may be a problem that we want to solve.

One way to solve this is to surround the synchronous and promise code with try-catch.

For example, we can write:

function foo() {
  try {
    syncFn();
    return asyncFn()
      .then(result => {
        //...
      });
  } catch (err) {
    return Promise.reject(err);
  }
}

We have the foo function with the try-catch block which runs syncFn first and then asyncFn which returns a promise.

We return the promise chain in the try block.

And if the catch block is run, then we return a rejected promise.

This lets us keep the function async all the way through.

Run the Synchronous Code in the Callback

We can also run the synchronous code in the callback.

For instance, we can write:

function foo() {
  return asyncFn()
    .then(result => {
      syncFn();
      return asyncFn2();
    })
    .then(result => {
      //...
    });
}

If the synchronous syncFn functions run in the then callback and it throws an exception, then the returned promise will be rejected.

The start of the promise chain can also be in the Promise constructor.

For example, we can write:

function foo() {
  return new Promise((resolve, reject) => {
      syncFn();
      resolve(asyncFn());
    })
    .then(result => {
      //...
    });
}

We run syncFn in the Promise constructor callback so that we run the callback so that exceptions will be propagated if an error is thrown by syncFn .

Composing Promises

We can run multiple promises in various ways.

If we want to run multiple unrelated promises in parallel, we can use the Promise.all method.

For example, we can write:

Promise.all([
    asyncFn1(),
    asyncFn2(),
  ])
  .then(([result1, result2]) => {
    //...
  })
  .catch(err => {
    //...
  });

We pass in an array of promise-returning functions.

Then we pass that in Promise.all .

And then we call then with a callback that has an array of the resolved values of both values.

Then we call catch to catch the errors occurring with them.

We can loop through the resolved items with them.

For example, we can write:

Promise.all([
    asyncFn1(),
    asyncFn2(),
  ])
  .then((results) => {
    for (const result of results) {
      console.log(result);
    }
  })
  .catch(err => {
    //...
  });

We get the results array and looped through it with the for-of loop.

Promise.race()

Promise.race is another method to chain promises.

It takes an array of promises and returns a promise that’s resolved to the value of the promise that’s resolved first.

For example, we can write:

Promise.race([
    asyncFn(),
    delay(3000).then(function() {
      throw new Error('timed out')
    })
  ])
  .then(function(text) {
    //...
  })
  .catch(function(reason) {
    //...
  });

We have an array of promises with the asyncFn and delay which both return promises.

Then we call then with a callback to get the resolved value from the promise that’s resolved the earliest.

Conclusion

We can handle errors with promise-based functions in a few ways.

Also, we can run multiple promises in many different ways.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *