Reputation: 33
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
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
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