I have the following async function that successfully runs on every result returned by the "Quote.insertMany" mongoose method. However, once I run the function I get a "SAVED" output for each one followed by the following error for each one of them:
SAVED
SAVED
...
SAVED
(node:5151) 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:5151) UnhandledPromiseRejectionWarning: MongoError: Cannot use a session that has ended
...
Closing connection
What's wrong with the function below? i.e. how can I handle these rejections:
(async function(){
db.connect();
await Quote.insertMany(quotes).
then(results => {
return Promise.all((results).map(function(quote) {
return Author.findOne({id: quote.authorid}, function(err, author){
if (err){
return next(err);
}
if(author != null){
try{
author.quotes.push(quote._id);
author.save();
console.log("SAVED");
}
catch(e){
return next(e);
}
}
})
}))
}).
catch(e => {
console.log(e);
});
console.log("Closing connection");
db.close();
})();
This was simple. I didn't realize "save()" was returning a promise.
Fix:
author.save().then().catch(e => {
console.log(e);
});
Related
I have an existing Node Express Application and want to improve the error handling better. My current route endpoint definition is like below,
app.get('/example/getActiveId', async (req, res, next) => {
// Some code to fetch some details from request and do some validations
try {
const result = await api.getActiveId(id);
res.json({ success: true, result }); // I am getting this response in all the time.
} catch (err) {
console.log('getActiveId', err)
console.error(err);
res.json({ success: false });
}
});
Also, I defined error middleware at the last of all the route paths.
// error handler middleware
app.use((error, req, res, next) => {
console.log('in Error middleware')
console.error(error.stack);
res.status(500).send(error.message || 'Something Broke!');
})
My definition of getActiveId is as below.
exports.getActiveId = id => axiosInstance
.get('/example')
.then(({ data }) => data)
.catch(er => er);
The problem in the above getActiveId definition is every time the catch of the getActiveId, the execution falls into the try block of the above endpoint definition. I wanted the execution should go into the catch block endpoint definition function. So that I could call next(err) to call the default express error handling middleware.
So I tried the following mockup code to mimic the same with promise reject.
exports.getActiveId = id => {
const __mockPromise = () => {
return new Promise((resolve, reject) => {
reject('Problem in getActiveId')
})
}
return new Promise((resolve, reject) => {
__mockPromise().then(({ data }) => resolve(data)).catch(er => { console.log('in catch....'); reject(er) })
});
}
I expected the above function will go into the catch block of the end point function definition.
But this time I am getting the following error,
in catch....
(node:32897) UnhandledPromiseRejectionWarning: Problem in getActiveId
(node:32897) 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: 4)
How can I fix this error and bypass the execution to error middleware?
With your current code, api.getActiveId always returns a resolved promise
if the axiosInstance.get succeeds, it resolves to the data
if the axiosInstance.get fails, the .catch(er => er) makes it resolve to the er.
If you want api.getActiveId to return a promise that is rejected with er, omit the .catch(er => er).
For example, if you run Node.js with the following input
const getActiveId = () => Promise.reject("error")
.then(({ data }) => data);
async function test() {
try {
const result = await getActiveId();
console.log(result);
} catch (err) {
console.error(err);
}
}
test();
the console.error statement will be reached and no unhandled promise rejection will be reported.
I'm using node v10.19.0 and i have created async function (req) {} it has try catch block if the error occur, then it console the error but cant return that error.
In routes.js: router.post("/somefunction", middleware.somefunction);
In middleware.js:
module.exports.somefunction = async (req, res) => {
var someFuncResponse = await service.someFunction(req)
res.send(someFuncResponse)
}
In service.js:
module.exports.someFunction = async function (req) {
try{
//some code which gives error
let response = { id:1 }
return { status: true, data: response }
}catch(error){
// catches the error
let response = { id:2 }
console.log(error) // get print correctly
console.log(response) // get print correctly
return { status: false, data: response } //not returning this
}
}
when i am hit this api on postman, i am getting "Could not get response" message.
also i am getting below msg on console:
(node:55009) 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: 1)
(node:55009) [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.
Try to wrap return values with Promise.resolve:
module.exports.someFunction = async function (req) {
try{
//some code which gives error
let response = { id:1 }
return Promise.resolve({ status: true, data: response })
}catch(error){
// catches the error
let response = { id:2 }
console.log(error) // get print correctly
console.log(response) // get print correctly
return Promise.resolve({ status: false, data: response }) //not returning this
}
}
This question already has answers here:
Using async/await with a forEach loop
(33 answers)
Closed 3 years ago.
I have the following code writed in nodejs express and firebase
route.js
try{
const test = await invoiceData.setAssignsInvoiced();
res.json({
status: true,
message: "Successful Invoice Generation"
});
}catch (e) {
res.status(500).json({
status: false,
message: "Internal Server Error",
data: e
});
}
InvoicesStorage.js
setAssignsInvoiced = async() => {
return new Promise(async (resolve,reject)=>{
try {
await _getAssignsForInvoiced(this);
this.assignsForInvoiced.forEach(async assing => {
let aux = assing._key.path.segments.length;
let ref = assing._key.path.segments[aux - 1];
await _updateAssignsToInvoiced(assing.data(),ref);
});
resolve(true)
} catch (error) {
console.error(error)
reject(error)
}
})
};
const _updateAssignsToInvoiced = async (assing, ref) => {
try {
const { invoiceNum } = assing.data(); //Here's an intentional error
await db
.collection("leadAsign")
.doc(ref)
.update({
invoiced: true,
updateDate: Date.now() - 240 * 60 * 1000,
invoiceNum
});
} catch (error) {
console.error(error);
throw new Error("Error at update to invoiced assigns");
}
};
How I hope it works:
According to me, I should throw out a synchronous error because my code has "await" and stop the system.
The answer I have:
the code runs asynchronously, that is, after calling the function the "await" has no effect and answers a "res.json" with status 200 and it is only after it throws the next error.
TypeError: assing.data is not a function
at _updateAssignsToInvoiced (D:\$Workzone\gd_fridays_h\src\controllers\invoices\InvoicesStorage.js:90:35)
at D:\$Workzone\gd_fridays_h\src\controllers\invoices\InvoicesStorage.js:55:23
at Array.forEach (<anonymous>)
at D:\$Workzone\gd_fridays_h\src\controllers\invoices\InvoicesStorage.js:51:37
true
POST /generateSingle 200 5182.650 ms - 57
(node:5600) UnhandledPromiseRejectionWarning: Error: Error at update to invoiced assigns
at _updateAssignsToInvoiced (D:\$Workzone\gd_fridays_h\src\controllers\invoices\InvoicesStorage.js:102:11)
at D:\$Workzone\gd_fridays_h\src\controllers\invoices\InvoicesStorage.js:55:23
at Array.forEach (<anonymous>)
at D:\$Workzone\gd_fridays_h\src\controllers\invoices\InvoicesStorage.js:51:37
(node:5600) 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: 4)
(node:5600) [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.
async/await doesn't work as you're expecting it to inside a forEach loop. An abundance of info on that specific issue here: https://stackoverflow.com/a/37576787/4043746
To fix your problem, you could use a for/of loop:
setAssignsInvoiced = async () => {
return new Promise(async (resolve, reject) => {
try {
await _getAssignsForInvoiced(this)
for (const assign of this.assignsForInvoiced) {
let aux = assign._key.path.segments.length
let ref = assign._key.path.segments[aux - 1]
await _updateAssignsToInvoiced(assign.data(), ref)
}
resolve(true)
} catch (error) {
console.error(error)
reject(error)
}
})
}
However, I'd also be tempted to suggest not returning a promise, as you're essentially doing that due to it being an async function. Something like this should work and is cleaner imo:
setAssignsInvoiced = async () => {
try {
await _getAssignsForInvoiced(this)
for (const assign of this.assignsForInvoiced) {
let aux = assign._key.path.segments.length
let ref = assign._key.path.segments[aux - 1]
await _updateAssignsToInvoiced(assign.data(), ref)
}
} catch (error) {
console.error(error)
// Re-throwing the error to pass the error down, just like you've
// done inside your _updateAssignsToInvoiced function's catch
throw new Error('Error setting assigns')
}
}
Async/await inside a forEach() loop will not wait until all the async operations inside the loop is completed.
One approach would be using Promise.all() like so:
const setAssignsInvoiced = async () => {
try {
await _getAssignsForInvoiced(this);
await _updateAssignsList(this.assignsForInvoiced);
return true;
} catch (error) {
console.error(error);
return new Error(error);
}
};
const _updateAssignsList = assignsList => {
return Promise.all(
assignsList.map(async assign => {
let aux = assign._key.path.segments.length;
let ref = assign._key.path.segments[aux - 1];
return await _updateAssignsToInvoiced(assign.data(), ref);
})
);
};
I've just extracted the async loop process to a separate function which return a Promise.
im trying to get the promise error, and throw to the "try catch" to concentrate the return of the error in one place.
like this:
async schedule(req, res) {
try {
//here is the function that returns a promise
service.search()
.then(async data => {
if (data.length > 0) {
res.status(200).json("OK!");
}
})
.catch(async error => {
//here i want to throw this error to the "try catch" to return the error message
throw new Error(error);
})
}
catch (error) {
res.status(400).json(error);
};
}
but when goes to "throw new Error(error);" gives me the message:
(node:15720) 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)
warning.js:27
someone could help me to understand what im doing wrong?
thank so much!
Rafael
UPDATE
based on the Marcos answer, i did:
async schedule(req, res) {
try {
const data = await service.search();
if (data.length > 0) {
res.status(200).json("OK!");
}
}
catch (error) {
res.status(400).json(error);
};
}
and worked... Now i understand how to handle this errors... thanks!
You either use async/await with a try/catch or .then/.catch, you don't mix both ways.
async schedule(req, res) {
try {
//here is the function that returns a promise
// If service.search rejects, it will go to the `catch`
const data = await service.search()
if (data.length > 0) {
return res.status(200).json("OK!");
}
// do something here
// res.status(400).send('Invalid data')
// throw new Error('Invalid data')
} catch (error) {
res.status(400).json(error);
}
}
or
schedule(req, res) {
service.search()
.then(data => {
if (data.length > 0) {
res.status(200).json("OK!");
}
})
.catch(error => {
res.status(400).json(error);
})
}
I want to use async and await to handle the promises. I would like to use this on the given example below:
exports.getUserData = async function(userId){
let query = {};
if(userId){
query.where = {userid : req.query.id}
}
let data;
try{
data = await entity.DB_User.findAll(query);
}catch(error){
console.log(error);
}
}
On execution its giving me an error
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: 3)
First thing first, you should return data.
I think that the Exception is raised when you call getUserData. Try:
getUserData()
.then(data => console.log)
.catch(err => console.log) // this line prevent the UnhandledPromiseRejection
// or in async context
try {
const data = await getUserData()
console.log(data)
} catch (err) {
console.log(err)
}