bhullar
bhullar

Reputation: 33

how to handle errors in multiple async await whle promise rejected without using try catch blocks?

i am new to express and was making user signup api. In this i need to hash user password and generate a random string. these both things are done by aync/await.If one promise got rejected then it returns the response in error handling but shows me warning for unhandled rejected promise.

methods.signup = async (req,res,next) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
        return res.status(config.errorCodes.validation).json({errors:errors.array()});
    }
    let payload = req.body;
    var newUser = new User({
        username:payload.username,
        fullname:payload.fullname,
        email: payload.email,
        password: payload.password,
        urltoken:{
            token:null
        },
        actStatus: 0,
        provider: 'email',
       role:1
    });
    let hash = commonMethods.generatePasswordHash(payload.password);
    let token = commonMethods.createRandomString();

    let [a,b] = await Promise.all([hash,token]).catch(err=>{
        res.status(400).json({status:false,msg:"error in promise"})
     });

    newUser.password = a;
    newUser.urltoken.token = b;
    newUser.save(function(err){
        if(err) {
            return res.status(config.errorCodes.success).json({ status:false 
        ,msg:"Error in saving userdata. Please try again",err});
        }
        else {
            commonMethods.sendMail(newUser);
            return res.status(config.errorCodes.success).json({"status":true, 
        "msg":"Registered succesfully. Please Check your Email to verify 
        your account.",newUser})
    }
}); 
}

and promise are -

commonMethods.createRandomString = function(password){
    return new Promise(function(resolve, reject) {
    var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
    var string_length = 25;
    var randomstring = '';
    for (var i=0; i<string_length; i++) {
        var rnum = Math.floor(Math.random() * chars.length);
        randomstring += chars.substring(rnum,rnum+1);
    }
   reject(randomstring);
   // resolve(randomstring);

})
}

which is always rejected for creating error.

Here is get below error

UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
(node:15172) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

how to catch these errors without using try catch or then for promises and keeping my code simple and easy to read.

Upvotes: 0

Views: 5013

Answers (2)

Aravindh Ravichandran
Aravindh Ravichandran

Reputation: 77

Coding Convention Suggestion for API

1) There are two ways to handle errors neatly. The first one is by wrapping all the async routes with a try catch block which will handle both synchronous and asynchronous code errors.

Async/Await

methods.foo = async(req, res, next) => {
try {
    // assuming bizz is a utility analogous to createRandomString
    // and returns a promise object which will either get resolved or rejected
    // if resolved the response will end in this case and end the response
    // if rejected, await will throw an error which will be caught by the catch block
    var bar = await bizz(); // Asynchronous code(which will wait for a promise to be resolved)

    // {... DO SYNCHRONOUS STUFF ...}

    // if suppose there is an error in your synchronous code,
    // then it will throw an error which also will  be caught by the catch block
    res.end();
} catch (err) {
    // {... DO WHAT YOU NEED TO WITH THE ERROR CAUGHT BY EITHER Asynchronous OR Synchronous part of the method ...}
    console.log(err);
    res.end(err);
  }
}

2) The second way is to have a middleware that wraps all the routes so that rewriting try catch for all the routes is avoided. Here both synchronous and asynchronous errors will be handled by the .catch() part in the async Middleware.

Using Async Await Middleware

const asyncMiddleware = (asyncFunction) => {
return (req, res, next) => {
    Promise.resolve(asyncFunction(req, res, next))
    .catch((err) => {
        // DO STUFF WITH ERROR
        res.end(err);
    });
  }
};
methods.foo = asyncMiddleware((req, res, next) => {
  // assuming bizz is a utility analogous to createRandomString
  // and returns a promise object which will either get resolved or rejected
  // if resolved the response will end in this case and end the response
  // if rejected, await will throw an error which will be caught by asyncMiddleware
  var bar = await bizz(); // Asynchronous code(which will wait for a promise to be resolved)

  // {... DO SYNCHRONOUS STUFF ...}
  // if suppose there is an error in your synchronous code
  // then it will throw an error which also will be caught by asyncMiddleware
  res.end();
});

Upvotes: 1

CertainPerformance
CertainPerformance

Reputation: 370809

The problem is the lines

let [a,b] = await Promise.all([hash,token]).catch(err=>{
  res.status(400).json({status:false,msg:"error in promise"})
});

If either hash or token throw, then the .catch function is entered, but the catch function doesn't return anything: so, after the await and catch have finished, the interpreter will see something like

let [a,b] = undefined

which won't work (undefined is not iterable), so the whole .signup method rejects. You need some way for the rest of the signup function to know to stop executing if there was an error in hash or token, maybe something like

const result = await Promise.all([hash,token]).catch(err=>{
  res.status(400).json({status:false,msg:"error in promise"})
});
if (!result) return;
let [a,b] = result;

You say you don't want to use try/catch, but the logic might be a bit easier to follow that way, since you could return immediately from inside the catch:

let a, b;
try {
  ([a, b] = await Promise.all([hash,token]));
} catch(e) {
  return res.status(400).json({status:false,msg:"error in promise"});
}

Upvotes: 3

Related Questions