I am struggling with some code... The 2 examples below I would think would work the same but the second example throws an error? I am also struggling to figure out the error, it's not bubbling up? Admittedly I am not a seasoned node developer so any guidance would be much appreciated! If it's relevant the create method in the module is calling the sequelize create.
This works
var p1 = deliverabiltyConfigs.create2(cfgObject);
return Promise.all([p1]).then(function([res1]) {
res.json({result: res1})
});
This does not
deliverabiltyConfigs.create2(cfgObject).then(res1 =>{
res.json({result: res1})
})
Here is the function that I am calling in a controller module
exports.create2 = (dConfig) => {
DeliverabilityConfig.create(dConfig)
.then(data => {
return data
})
.catch(err => {
return {
message:
err.message || "Some error occurred while createing this config."
};
});
};
The create2 function always returns null, so neither invocation will work. Promise.all([p1]) hides the problem, returning a promise to perform an array of no promises.
create2(cfgObject).then(res1 =>{ attempts to invoke then() on null, generating a more obvious error. But neither way works.
Fix by deciding which promise syntax you want, using each as follows:
Using original promise syntax....
exports.create2 = dConfig => {
// note the return
return DeliverabilityConfig.create(dConfig)
.catch(err => {
const message = err.message || "Some error occurred while createing this config.";
return { message };
});
};
// caller
deliverabiltyConfigs.create2(cfgObject).then(result =>{
res.json(result);
})
With recent syntactic sugar...
exports.create2 = async (dConfig) => {
try {
// its fine to not await here, since the caller will await
// but just to illustrate how you might perform more async work here...
return await DeliverabilityConfig.create(dConfig);
} catch (err) {
const message = err.message || "Some error occurred while createing this config."
return { message }
}
}
// caller
var result = await deliverabiltyConfigs.create2(cfgObject);
res.json(result);
Use Promise.all() to run >1 promise concurrently. You've only got one promise in the OP, so no reason for it here.
Related
class AuthController {
static methods = {
GET: {
'/auth/signup': {
func: AuthService.signUp,
response: (data, res) => {
res.statusCode = 200;
res.end(JSON.stringify(data));
},
},
},
};
static use(req, res) {
const route = this.methods[req.method][req.url];
if (!route) {
res.statusCode = 404;
res.end(JSON.stringify({ message: 'Not found 404!' }));
return;
}
try {
const data = JSON.parse(req?.body?.data || '{}');
const result = route.func({ ...data });
route.response(result, res);
} catch (err) {
console.log(err, 'here');
res.statusCode = err.statusCode || 500;
res.end(JSON.stringify(err.message));
}
}
}
class AuthService {
static async signUp({ login, password }) {
if (!login || !password) throw new BaseError(400, 'kl', 'Custom error');
}
}
It shows the error in console but try catch block doesn't see it.
Here is the traceback.
I don't know what the reason is because the function which throws error is inside of the block. Help please!
The trace back that you attached tells you exactly what the problem is and what you need to do:
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()
You can't catch an exception thrown by an async function with a try..catch block outside of that function, because script execution reaches the catch block before the async execution is finished. You therefor have to use .catch(..) instead:
const result = route.func({ ...data }).catch((err) => {
console.log("catched error: ", err);
});
I see one issue. You have declared signUp() to be async. That means it always returns a promise and it means that any throw operations inside it reject that promise that it returns (the exception doesn't propagate synchronously). But, when you attempt to call it here:
const result = route.func({ ...data });
You don't await it so when signUp() rejects, the promise goes into result, but nobody ever handles the fact that the promise rejected and you get UnhandlePromiseRejectionWarning from the system.
I can't see the whole overall design (of all the other routes), but perhaps you just need to add await to this:
const result = await route.func({ ...data });
And, you would have to make .use() be async also.
Or, if signUp() doesn't actually need to be async, then just remove the async from its declaration and the throw will be synchronous (instead of being turned into a rejected promise) and your try/catch will catch it then.
I have a function like this:
async getPatient(patientId: string): Promise<PatientDTO> {
const patient = await PatientDAO.getPatients({ id: patientId })
if (patient.length === 0) {
throw new NotFoundError("Patient Not Found!")
}
return patient[0]
}
But I got an error
UnhandledPromiseRejectionWarning: Error: Patient Not Found!
This happened cause I have used async function. How can I make this code running properly?
In order to manage errors in an async function, you have to use a try/catch block:
async getPatient(patientId: string): Promise<PatientDTO> {
try {
const patient = await PatientDAO.getPatients({ id: patientId })
return patient[0]
} catch (error) {
// Do whatever you may want with error
throw error;
}
}
I should mention, that if you simply want to throw the error thats received from getPatients theres no need for a try/catch block at all. Its only needed if you wish to modify the error or perform an extra action according to the error that was thrown.
You have 2 options:
First one is try/catch block with await keyword. Please notice that await has to be used in async function.
try {
const patient = await getPatient(foo);
// handle your data here
} catch(e) {
// error handling here
}
Second one is catch function
getPatient(foo)
.then(patient => {
// handle your data here
}).catch(error => {
// error handling here
});
I am using q and I have multiple mongoose .exec() promises that never gets to the .then() part of the code, so never allow the q to resolve. Can't figure out why it never comes back.
var defer = q.defer();
var promises = [];
console.log('Exams:', exams.length);
for (var e=0; e<exams.length; e++) {
console.log('Exams:', exams[e]._id);
var newPromise = Pupilexam.find({ _exam: exams[e]._id }).populate('_user').exec()
.then((pupils) => {
console.log("Adding pupils", exams[e]._id);
exams[e].pupils = pupils;
resolve(exams[e]);
})
.catch((err) => {
reject(err);
});
console.log(typeof newPromise);
promises.push(newPromise);
console.log("Promised pushed");
}
q.all(promises).then(function(data){
console.log("q'd all");
defer.resolve(res.status(200).json(exams));
});
return defer;
The Pupilexam.find().exec() never reaches the .then() so the promises never resolve and the defer never resolves. Why would the mongoose find not get to the .then()? What have I missed?
*** UPDATE ***
Even using the built in promises, we get the same issue. The Pupilexams.find() call never comes back.
var promises = [];
for (var e=0; e<exams.length; e++) {
console.log('e:', e);
console.log('Exam', exams[e]._id);
var newPromise = Pupilexam.find({ _exam: exams[e]._id }).populate('_user').exec()
.then((pupils) => {
console.log("Adding pupils", exams[e]._id);
exams[e].pupils = pupils;
})
.catch(handleError(res));
promises.push(newPromise);
}
Promise.all(promises).then((exams) => {
console.log(values);
res.status(200).json(exams)
});
With this method I also get a headers error on the call UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
** ADDITIONAL CODE REQUESTED **
function handleError(res, statusCode) {
statusCode = statusCode || 500;
return function(err) {
console.log(err.message);
res.status(statusCode).send(err);
};
}
To answer the updated question regarding the Cannot set headers after they are sent to the client error. Looks like you send a response to the client inside your handleError function. Now, if more than one Pupilexam.find call fails, handleError would be invoked twice, resulting in the mentioned error.
You should move the catch-handler down to the Promise.all call:
const promises = [];
for (const exam of exams) {
const newPromise = Pupilexam
.find({ _exam: exam._id }).populate('_user').exec()
.then((pupils) => {
exam.pupils = pupils;
});
promises.push(newPromise);
}
Promise.all(promises)
.then((exams) => {
res.status(200).json(exams);
})
.catch(handleError(res));
I guess that you are indeed returning your promise but you are returning an empty json.
There are 2 problems with your approach:
You are not returning from your then: should return pupils and it is returning undefined
You are logging values that I don't know what it is
.then((pupils) => {
console.log("Adding pupils", exams[e]._id);
exams[e].pupils = pupils;
// you should return something // return pupils
})
promises.push(newPromise);
Promise.all(promises).then((exams) => {
// ['undefined', 'undefined', ...]
console.log(values);
res.status(200).json(exams)
});
Looks like the answer was that on these two lines the exams[e] is not in scope, because by the time the promise comes back the loop has moved on, so e is wrong and gets too high so it was erroring.
console.log("Adding pupils", exams[e]._id);
exams[e].pupils = pupils;
Only discovered that when I read #eol's message about the catch and decided to catch it properly and output.
it is Look from your code.
//(async) function
for (var e of exams) {
try {
const pupils = await Pupilexam.find({ _exam: exams[e]._id
}).populate('_user').exec().lean()
e.pupils = pupils
}catch((err){
//handleError
};
}
res.status(200).json({data: exams})
maybe that will show you how match are you wrong
const fetch = require('node-fetch');
let url = 'something.com';
module.exports = function(context) {
let a = fetch(url)
a.then(res => {
if(res.status!=200) throw new Error(res.statusText)
else{
context.done(null, res.body);
}
});
a.catch(err => {
console.log(err)
throw new Error(err)
});
};
I have a durable function that calls an activity function like above. I have set automatic retry on failure on this activity function. To retry the function needs to get an error.
So In get request I want to throw an error when i get response like 404 or something similar. But when i throw from catch block i get an error like below
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().
function pauses there and stops execution.I have to manually stop and start the execution. How can i handle this so that the function retries?
Your code branches.
Ignoring the detail, what you have is :
let a = <Promise>; // root
a.then(...); // branch_1
a.catch(...); // branch_2
So whereas you catch errors arising in a, any error arising in branch 1 will be uncaught. Hence the warning
Compare that with :
let a = <Promise>; // root
a.then(...).catch(...); // branch
or
<Promise>.then(...).catch(...); // no assignment necessary
So, you might write :
module.exports = function(context) {
return fetch(url)
.then(res => {
if(res.status!=200) {
throw new Error(res.statusText);
} else {
context.done(null, res.body);
}
})
.catch(err => {
console.log(err)
throw new Error(err)
});
};
Alternatively, depending on the required division of responsibilities between module and caller(s) ...
module.exports = function(context) {
return fetch(url)
.then(res => {
if(res.status!=200) {
throw new Error(res.statusText);
} else {
return res;
}
});
};
... and call .context.done(null, res.body); in a .then() callback in the caller.
In both cases, with return included, then the caller will need to catch errors otherwise you will again get an unhandled error warning.
Found that with the use of async/await this problem goes away and the function re-try after exception is thrown.
const fetch = require('node-fetch');
let url = 'something.com';
module.exports = async function(context) {
let res = await fetch(url)
if(res.status!=200) throw new Error(res.statusText);
else return res.body;
};
export function getAllHost(req, res) {
function findAllHost() {
let query = {};
query.company = req.query && req.query.companyId ? req.query.companyId : res.locals.payload.companyId;
query.active = true;
if(req.query && req.query.name) {
let regexp = new RegExp('\\b' + req.query.name);
query['name'] = {$regex: regexp, $options: 'i'};
}
return Host.find(query);
}
async function sendRes() {
let allHost = [];
let hosts = [];
try {
hosts = await findAllHost();
} catch(err){
console.log(err)
}
for (let host of hosts) {
allHost.push(new Host_V1(host));
}
return allHost
}
sendRes().then(data => res.status(200).json(data)).catch(error => {
console.log("error is", error);
res.status(error.status || 500).json({
message: error.status ? error.message : 'Server Error'
});
});
}
I have been trying to adapt async/await into my code, so I converted one of the Promise based api controller to make use of async/await, but the thing that bothers me is that my server responds with 500, and the console.log inside my catch block doesn't print anything.
No error gets thrown.
I am using babel babel-plugin-syntax-async-functions to parse it.
What is it that I am doing wrong?
Your code is a bit overcomplicated, but judging by it you should receive an error in the console if one appears. It could instead be that you have a middleware producing an error? The main issue is that you're catching the error in the async function sendRes, so the .catch-method you call on the returned Promise will never be fired even if there is an error.
Like many others that are new to async/await, you've misunderstood and believe that you have to wrap every await expression in a try/catch-block. This is not the case. The error "trickles" up the call chain, and unless a particular function can provide a different return value, it's best to catch the error from the top-most callee. Take this simple example which shows a common anti-pattern: https://repl.it/repls/PunySafeInterfacestandard (await and async isn't even needed in these examples, but I added them for clarity)
But if you try to simplify your code, maybe something like the below snippet, you might be able to rule out if it's a middleware or not.
export async function getAllHosts (req, res) {
try {
let query = {
company: req.query && req.query.companyId ? req.query.companyId : res.locals.payload.companyId,
active: true
}
if (req.query && req.query.name) {
let regexp = new RegExp('\\b' + req.query.name)
query.name = {$regex: regexp, $options: 'i'}
}
let allHosts = (await Host.find(query)).map((host) => new Host_V1(host))
return res.json(allHosts)
} catch (e) {
console.log("error is", e)
res.status(error.status || 500).json({
message: error.status ? error.message : 'Server Error'
})
}
}
Take note of the (await Host.find(query)) line. If the Promise that's returned from Host.find() rejects, the .map()-method won't be executed on the data and execution will jump to the catch-block.
I also heavily discourage using Babel since async/await has been natively supported in Node since version 7.6.
EDIT : The value returned is indeed a promise
I think that the error is related to your 'SendRes.then' since what SendRes returns is not a promise but it's actually is the Array allHost
Your data argument is not an argument anymore it is the value returned from the sendRes function thanks to your async / await implementation.
const hosts = sendRes();
res.status(200).json(hosts);
if you want to handle an error you must return something from your catch block so that you can can handle it here.
if (!hosts) res.status(500);
To simplify your code you can also get rid of the sendRes function and make your getAllHost express middleware an async function
async getAllHost(req, res) { /*...*/ }
try {
let allHosts = await findAllHosts();
res.status(200).json(allHosts);
} catch (error) {
res.status(500).send({ error })
}