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 function
s 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(...)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With