There is the following function, which doesn't catch MyException.
const myFunction = () => async (req, res, next) => {
try {
myHTTPRequest().then(async (response) => {
if (response.data.results.length != 1) {
throw new MyException('MyError');
}
res.end('All good');
})
.catch((error) => {
throw error; //Doesn't work
});
} catch (error) {
console.log('This block should catch MyException, but it doesn't');
next(error);
}
};
Instead, the application writes following error message into the console
(node:45746) UnhandledPromiseRejectionWarning
(node:45746) 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:45746) [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.
The question is, how does the code need to be adjusted to catch MyException in the expected Catch-Block?
The issue is that you're mixing .then/.catch with try/catch.
If you want the code to enter the try/catch in an async function, you have to use the await keyword on the Promise.
You can drop the .catch since it's doing nothing, you're throwing again the error, and that's causing the UnhandledPromiseRejectionWarning
const myFunction = () => (req, res, next) => {
try {
const response = await myHTTPRequest();
if (response.data.results.length != 1) {
throw new MyException('MyError');
}
res.end('All good');
} catch (error) {
next(error);
}
};
Using .then/catch without async/await the code would be:
const myFunction = () => (req, res, next) => {
myHTTPRequest().then((response) => {
if (response.data.results.length != 1) {
throw new MyException('MyError');
}
res.end('All good');
})
.catch((error) => {
throw error;
// It makes no sense to throw again in here
// But I'm showing you how to handle it if you do
})
.catch(error => {
next(error);
})
};
Of course the double .catch doesn't make sense, and you should remove it, leaving a single one:
const myFunction = () => (req, res, next) => {
myHTTPRequest().then((response) => {
if (response.data.results.length != 1) {
throw new MyException('MyError');
}
res.end('All good');
})
.catch(error => {
next(error);
})
};
Related
I am using below for JWT:
let jwtoptions = {};
jwtoptions.jwtFromRequest = ExtractJWT.fromAuthHeaderAsBearerToken();
jwtoptions.secretOrKey = DB.secret;
let Strategy = new JWTStrategy(jwtoptions,(jwt_payload,done)=>{
User.findById(jwt_payload.id)
.then(User =>{
return done(null, User);
})
.catch(err =>{
return done(err,false);
})
})
passport.use(Strategy);
But its showing me below error:
(node:14224) UnhandledPromiseRejectionWarning: TypeError: done is not a function
(node:13568) 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().
Haven't used passport-jwt but from reading the docs it seems you need to use a callback instead of a promise
let Strategy = new JWTStrategy(jwtoptions,(jwt_payload,done)=>{
User.findById(jwt_payload.id, (err, user) => {
if (err) return done(err, false);
return done(null, user);
});
});
The problem is that i am getting UNhandledPromiseRejection error eveen though i think i have handled all the cases. The code flows from profileRoutes to Controller to Utils where the error comes first.
Inside the profileRoutes.js
router.get('/:username', async (r, s) => {
try{
let profileData = await getProfileData(r.params.username);
s.json({ success: true, payload: profileData });
}catch(err){
console.log('ending request processing by responding a error');
s.status(500).json({ success: false, message: 'err[0].message' });
}
});
Inside the controllers/index.js
const fetchQueue = [getUserRepos];
async function getProfileData(username) {
let profileData = {};
try{
let results = await Promise.all(fetchQueue.map(item => item(username)));
for (let i = 0; i < results.length; i++) {
profileData[getKeys[i]] = results[i];
}
return profileData;
}catch(err){
console.log('error log in controller/index getProfileData function');
throw err;
}
}
const getUserRepos = async (username) => {
try {
// const res = await utils.gqlSender(username, 'userRepos', { createdAt });
const res = await utils.gqlSender(username, 'userReposData');
return res.user.repositories;
} catch (err) {
console.log('error log in controller/index getUserRepos function');
throw err;
}
};
Inside the utils/index.js
const gqlSender = async (username, type, opt = {}) => {
axios.post('', {
query: gqlQuery(username, type, opt) // generates a needed graphQL query
}).then(res => {
if(res.data.errors) { // this is where the error is recieved and so i reject promise.
console.log('bef###re');
return Promise.reject (res.data.errors);
}
console.log('###',res.data);
return res.data;
}).catch(err => {
console.log('error in making axios request inside utils/index gqlSender function');
throw err;
// return Promise.reject(err);
});
The stack trace on making get request to /:username is-
error log in controller/index getUserRepos function
error log in controller/index getProfileData function
ending request processing by responding a error
bef###re
error in making axios request inside utils/index gqlSender function
(node:11260) UnhandledPromiseRejectionWarning: [object Array]
(node:11260) 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:11260) [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.
I dont think i am missing any Promise Rejection.
Any help is appreciated. Thanks.
i have referred these answers previously -
What's the difference between returning value or Promise.resolve from then()
Do I need to return after early resolve/reject?
Your gqlSender function is not returning the promise that will get rejected, so it is not handled anywhere. You should write either
const gqlSender = (username, type, opt = {}) => {
return axios.post('', {
// ^^^^^^
query: gqlQuery(username, type, opt) // generates a needed graphQL query
}).then(res => {
if (res.data.errors) {
console.log('error in making axios request inside utils/index gqlSender function');
throw res.data.errors;
} else {
console.log('###',res.data);
return res.data;
}
});
};
or
const gqlSender = async (username, type, opt = {}) => {
// ^^^^^
const res = await axios.post('', {
query: gqlQuery(username, type, opt) // generates a needed graphQL query
});
if (res.data.errors) {
console.log('error in making axios request inside utils/index gqlSender function');
throw res.data.errors;
} else {
console.log('###',res.data);
return res.data;
}
}
I have a service that analyses websites, compresses their sources like CSS Documents, Images etc. I have 2 functions, one is Socket.IO socket.on() method with async callback function. Another is main function for service.
socket.on('run', async options => {
debug(`${options.target} Adresine Bir Kullanıcı İstek Yaptı!`);
let user = null;
console.log(options);
if(options.token) {
user = await User.findById(jwt.verify(options.token, config.get('jwtPrivateKey'))._id);
options.userId = user._id.toString();
} else if(options.visitor) {
user = await Visitor.findById(options.visitor._id);
if(user.report) {
return socket.emit('error', new Error('You have exceeded your report limit'));
} else {
options.userId = user._id.toString();
}
}
if(options.userId) {
let userType = await UserType.find({ name: user.type });
if(userType.length > 0 && ((user.type == 'Visitor' && user.report == undefined) || (user.reports.length < userType[0].rights.reportsLimit.limit || userType[0].rights.reportsLimit.unlimited))) {
options.rights = userType[0].rights;
let { error, data } = await wrapper(runService(options.target, options, socket));
if(error) {
console.log('Here', error);
return socket.emit('error', error);
}
.
.
.
}
.
.
.
}
});
In the above function,
let { error, data } = await wrapper(runService(options.target, options, socket));
if(error) {
console.log('Here', error);
return socket.emit('error', error);
}
This part is important, because I call my main async service function runService with my async function wrapper function that is named wrapper. The wrapper function is this;
const wrapper = promise => (
promise
.then(data => ({ data, error: null }))
.catch(error => ({ error, data: null }))
);
In my main async service function, I only throw an error;
async function runService(target, options, socket) {
throw new Error('any error');
}
But the expected output is much different from actual output. Here is the output of this code;
Here Error: any error
at startService (C:\Projeler\OpDetect\Background-Service\lib\app.js:404:11)
at Socket.socket.on (C:\Projeler\OpDetect\Background-Service\app.js:73:57)
at process._tickCallback (internal/process/next_tick.js:68:7)
(node:16600) UnhandledPromiseRejectionWarning: Error: any error
at startService (C:\Projeler\OpDetect\Background-Service\lib\app.js:404:11)
at Socket.socket.on (C:\Projeler\OpDetect\Background-Service\app.js:73:57)
at process._tickCallback (internal/process/next_tick.js:68:7)
(node:16600) 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:16600) [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.
My expectation about the output is, like this;
Here Error: any error
at startService (C:\Projeler\OpDetect\Background-Service\lib\app.js:404:11)
at Socket.socket.on (C:\Projeler\OpDetect\Background-Service\app.js:73:57)
at process._tickCallback (internal/process/next_tick.js:68:7)
Because I already handled the promise rejection with my wrapper function and catched the rejection, Why is 2 more UnhandledPromiseRejectionWarning errors on rejection?
Also, the line,
return socket.emit('error', error);
is not calling for no reason. It should have been called when the if statement truthy. Why is not this socket.emit function called?
As best practice use try {} catch(){} with async/await.
For ex.
userUtils.signUp = async (userName) => {
try {
const callFunction = await userUtils.checkExistancy(userName);
if (!callFunction.isExist) {
...
} else {
...
}
} catch (err) {
console.log(err);
throw err;
}
};
in your case it will be like
socket.on('run', async options => {
try {
user = await User.findById(jwt.verify(options.token, config.get('jwtPrivateKey'))._id);
options.userId = user._id.toString();
return true;
} catch (err) {
throw err;
}});
I'm writing a function, that loops through port numbers until it finds an open one:
async function findPort (port, app, logger) {
const lookupPort = () => {
return portOpen = new Promise( (resolve, reject) => {
app.listen(port, () => {
logger.log("info", `Server listening on port: ${port}`);
resolve(true);
})
.on('error', (err) => {
logger.log("warn", "port closed: " + err.port);
reject(false);
});
});
}
let portOpen = false;
while (portOpen === false){
portOpen = await lookupPort();
port++;
}
When executed, it iterates through one port and then trows an exception:
(node:2869) UnhandledPromiseRejectionWarning: Unhandled promise rejection.
There are 2 issues with the code above:
1) while loop stops its execution because lookupPort function throws an error (promise is rejected on reject(false); line) which is not caught (UnhandledPromiseRejectionWarning: Unhandled promise rejection.). To fix this try to wrap the code inside while loop into try/catch construction:
while (portOpen === false){
try {
portOpen = await lookupPort();
}
catch (error) {
// handle an error here
}
port++;
}
Or if you do not want to handle the promise you reject inside lookupPort just remove reject(false); line.
2) lookupPort function assigns a new Promise() to portOpen variable. So even if error will be handled by try/catch, portOpen === false condition will evaluate to false because portOpen will be equal to a Promise object. If there is no reason to assin portOpen the value of the new Promise you should remove it.
Node 8.1.2, I have a structure where one file is calling another file's function in a map. In a real example I would use Promise.all on the map but that's not the question here. Here is the structure:
A.js:
const { b } = require('./B')
function expressStuff (req, res, next) {
things.map(thing => {
return b(thing)
}))
return res.status(200).json(...)
}
B.js:
// Thing -> Promise<Object>
function b (thing) {
return ThingModel.update(...) // this returns a Promise but FAILS and throws an errror
}
module.exports = { b }
OK. So in function b I try to get some async data (from a database). It fails and throws an Uncaught Promise Rejection.
How to make deal with it?
I tried multiple solutions:
A1.js:
const { b } = require('./B')
function expressStuff (req, res, next) {
things.map(thing => {
try {
return b(thing)
} catch (err) {
return next(err)
}
}))
return res.status(200).json(...)
}
But that is still uncaught.
A2.js:
const { b } = require('./B')
function expressStuff (req, res, next) {
try {
things.map(thing => {
return b(thing)
}))
} catch (err) {
return next(err)
}
return res.status(200).json(...)
}
Still unhandled. I tried using Promise.all, I tried double try-catch blocks (since I thought the one inside map might be returning next from the to the map result and not actually from expressStuff function. Still nothing.
The closes I got to the answer was handling the error but then code wouldn't wait for it to be thrown and both res.status() and next would work resulting in race conditions and cannot set headers after they are sent errors.
All I want to do is for the function b to throw an error but catch it in the expressStuff so I can rethrow custom UnprocessableEntityError and pass it to next. It seems like error from file B is not bubbling up to the map where it is called.
How do I do it?
EDIT:
The only way I can make this rejection handled is try-catching it in the B.js. But if I try to rethrow an error/return it - nothing. Error is swallowed. If I try to console.log it - it will be logged though.
DETAILS:
Thanks to marked answer I refactored my actual code and made it to work perfectly.
function expressStuff (res, req, next) {
try {
await Promise.all(things.map(async thing => {
if (ifSomething()) {
await b(thing)
}
}))
} catch (err) {
return next(new MyCustomError('My Custom Error Message'))
}
return res.status(200).json(...)
}
Handling rejections with try/catch works only in async functions when you await the promise - which you haven't attempted yet.
You could do either
async function expressStuff (req, res, next) {
var results;
try {
results = await Promise.all(things.map(b)); // throws when any of the promises reject
} catch (err) {
return next(err) // handle error
}
return res.status(200).json(...)
}
or (like Wait until all ES6 promises complete, even rejected promises)
function expressStuff (req, res, next) {
const resultPromises = things.map(async (thing) => {
try {
return await b(thing); // throws when the promise for this particular thing rejects
} catch (err) {
return defaultValue; // handle error - don't call `next` here
}
});
…
return res.status(200).json(...)
}