DEV Community

Arnaud
Arnaud

Posted on

Untangle async calls from the try/catch block

Promises are resolved using a then/catch block like so:

myPromise
  .then((data) => {
    // promise resolved
    doStuff(data);
  })
  .catch((error) => {
    // promise rejected
    throw error;
  });

The async/await keywords came along, and handling promises became a little easier, the code above can now be written like this:

try {
  const data = await myPromise;
  // promise resolved
  doStuff(data);
} catch (error) {
  // promise rejected
  throw error;
}

While this is arguably better, the try/catch block becomes really tiring to write after a while, so I've taken some inspiration from node to simplify this code a little bit. Node uses an idiomatic pattern called Error-first callbacks. By convention, callbacks get two parameters: the first one is the error, and the second one is the data. Our examples above also have an error and a data, so let's see how we can rewrite this:

const doAwait = async (promise) => {
  try {
    const data = await promise;
    return [undefined, data];
  } catch (error) {
    return [error, undefined];
  }
};

The doAwait function takes a promise, and returns an array with two elements, the first one is the error, and the second one is the data.

Using this simple function spares developers from writing try/catch blocks over and over again, and can just destructure the returned value into an array, and handle the error in a way that is similar to how callbacks are written in node:

const [error, result] = await doAwait(myPromise);

if (error) {
  throw error;
}

doStuff(result);

I find this little function quite handy, and the npm package to-await actually does just that, and it also provides a handy utility to resolve an array of promises! Visit its README for more code examples.

Latest comments (0)