background

New team member, found our team code specification to add try to async await… The catch. He felt puzzled. If there were many, wouldn’t there be many places to add? Isn’t that inelegant?

Why error handling

JavaScript is a single-threaded language, and without a try… Catch will cause an error to be reported and execution cannot continue. Of course it doesn’t mean you have to use try… Catch, use try… Catch means you know the location code is likely to get an error, so you use try… Catch to catch and let the program continue.

I understand that when we are performing async await, we are generally running in asynchronous scenarios, which should not block the process, so we recommend using try… Catch handling.

Async await more elegant error handling

But it is true, as the colleague said, that… Catch is not a very elegant act. So I googled it and found that How to write async await without try-catch blocks in Javascript has a more elegant way of handling it, And packaged into a library – await-to-JS. The library has only one function, which we can use in our business, as follows:

/ * * *@param { Promise } promise
 * @param { Object= } errorExt - Additional Information you can pass to the err object
 * @return { Promise }* /
export function to<T.U = Error> (
  promise: Promise<T>, errorExt? :object
) :Promise"[U.undefined"|"null.T] >{
  return promise
    .then<[null, T]>((data: T) = > [null, data]) // Execute successfully, return the first item of array null. The second is results.
    .catch<[U, undefined> ((err: U) = > {
      if (errorExt) {
        Object.assign(err, errorExt);
      }

      return [err, undefined]; // The first item of the array is error and the second item is undefined
    });
}

export default to;
Copy the code

An await is waiting for a Promise to return.

Normally, the await command is followed by a Promise object that returns the result of that object. If it is not a Promise object, the corresponding value is returned.

Therefore, we only need to use the features of Promise to return different arrays in promise.then and promise.catch respectively. During this period, the first item of the array will be returned as NULL and the second is the result. The first item in the array rejected is an error message and the second item is undefined. When using, judge whether the first item is empty to know whether there is an error. The specific use is as follows:

import to from 'await-to-js';
// If you use CommonJS (i.e NodeJS environment), it should be:
// const to = require('await-to-js').default;

async function asyncTaskWithCb(cb) {
     let err, user, savedTask, notification;

     [ err, user ] = await to(UserModel.findById(1));
     if(! user)return cb('No user found');

     [ err, savedTask ] = await to(TaskModel({userId: user.id, name: 'Demo Task'}));
     if(err) return cb('Error occurred while saving task');

    if(user.notificationsEnabled) {
       [ err ] = await to(NotificationService.sendNotification(user.id, 'Task Created'));
       if(err) return cb('Error while sending notification');
    }

    if(savedTask.assignedUser.id ! == user.id) { [ err, notification ] =await to(NotificationService.sendNotification(savedTask.assignedUser.id, 'Task was created for you'));
       if(err) return cb('Error while sending notification');
    }

    cb(null, savedTask);
}
Copy the code

summary

Adding error handling to async await is personally necessary, but schemes are more than just try… The catch. With the features of async await and Promise, we can handle the error of async await more elegantly.