I have an as promise as :
try {
myPromise().then(function(){
console.log("ok");
}, function(err) { throw err; });
} catch(e) {
console.log("error");
}
now my control goes to the function(err) and it throws the error but the error is not caught in catch().
Because promises are asynchronous, flow control doesn't work the way you're thinking it will. Your try...catch block is outside of the promise initialization code, and once it initializes the promise, it's done. So the try...catch block is only handling promise initialization in the code above. If the promise is rejected/errored (as you say it is doing in your code), the error function will fire within the error function closure only.
Consider a common error handler or you can refactor your try...catch block to be within the closure.
Here's the code with the common error handler:
try {
myPromise().then(function(){
console.log("ok");
}, function(err) {
errHandler(err);
});
} catch(e) {
errHandler(e);
}
function errHandler(err) {
console.log("error");
}
You have two options:
1) Use Promise.catch:
myPromise().then(function(){
console.log("ok");
}, function(err) { throw err; })
.catch(function(err) { console.log("error"); });
2) If you have transpiler use async/await:
async function parentFunction() {
try {
await myPromise();
console.log("ok");
}
catch (e) {
console.log("error");
}
}
Related
I have a try/catch block within which I run my synchronous function call, I wonder why it won't be caught by the catch if the function return an Error. In this case I have a known issue in mySyncFunction and I don't want to throw on that, because I want the test function to catch that
function test() {
try {
return mySyncFunction();
} catch (error) {
console.error('my error message', error);
return [];
}
}
function mySyncFunction() {
try {
// Do stuff
const expectedIssue = true;
if (expectedIssue) {
return Error('the known issue happended');
}
} catch (e) {
throw Error(e)
}
}
console.log(test());
If there is no error occuring during the call of this.mySyncFunction(args) it will returns normally. However, if there is an exception raised during this call, it will simply go directly to the catch, console.error your error and return [].
You're not throwing an Error, you're returning one. Errors and other exception are only caught when you throw them, not by simply being around.
The correct way to actually see the exception being caught is
function test() {
try {
return mySyncFunction();
} catch (error) {
console.error('my error message', error.message); // notice error.message
return [];
}
}
function mySyncFunction() {
throw new Error('my error'); // notice throw
}
console.log(test());
I have this code:
on('connection', async(socket) => {
try {
const promises = members.map(async(member) => {
try {
const users = await User.find({})
const _promises = users.map(async() => {
try {
//some code here
} catch (err) {
console.log(err)
}
})
await Promise.all(_promises)
} catch (err) {
console.log(err)
}
})
await Promise.all(promises)
} catch (err) {
console.log(err)
throw err
}
})
As you can see I have a try catch for each nested async function. Would it be possible to tweak the code to use only a single catch, or to simplify things somehow?
You can have just a single await at the top level of the handler. If the Promises spawned inside it all chain together to a Promise which is awaited at the top level (like in your example), that top await will catch errors thrown anywhere inside.
But, your catch section should not throw another error unless .on handles Promise rejections as well, otherwise you'll get an unhandled Promise rejection:
on('connection', async(socket) => {
try {
const promises = members.map(async(member) => {
const users = await User.find({})
const _promises = users.map(async() => {
//some code here which may throw
});
await Promise.all(_promises);
});
await Promise.all(promises);
} catch (err) {
console.log(err);
}
})
If await User.find throws, then the promises array will contain a Promise which rejects, which mean that the top await Promise.all(promises); will throw and be caught
If something inside users.map throws, _promises will contain a Promise which rejects, so await Promise.all(_promises); will throw. But that's inside the const promises = members.map callback, so that will result in promises containing a rejected Promise too - so it will be caught by the await Promise.all(promises); as well.
If a function you call throws an error, the error will fall back to the nearest catch block the function call is enclosed in.
try {
throw "an error";
}
catch(e) {
console.log(e); //output: "an error"
}
Now consider this
try {
try {
throw "an error";
}
catch(e) {
console.log(e); //output: "an error"
}
}
catch(e) {
console.log(e); //This line is not going to be executed
}
This mechanism enables attachment of more error information to the generated error in each level. Imagine your error is an object and each nested catch bock attaching its own information to the error object an pass it along by throwing again.
Look at the following code:
try {
try {
throw {internalError: 101};
}
catch(e) {
//Attach more info and throw again
e.additionalInfo = 'Disconnected when gathering information';
throw e;
}
}
catch(e) {
e.message = 'Cannot get information'
console.log(e); //Final error with lot of information
}
I'm trying to do some validations before creating/updating an entry as shown below:
async save(){
return new Promise((resolve, reject)=>{
if(!this.isCampaignValid){
this.handleError()
reject()
}
else{
this.$store
.dispatch('updateCampaign')
.then((res)=>{
resolve()
this.showNotification(res.message, 'success')
})
.catch(error=>{
this.showNotification(error.message, 'error')
reject()
})
}
})
},
the isCampaignValid is a computed value which computes the validity.
If the campaign is not valid, then I'm getting an error in the console as below:
Uncaught (in promise) undefined
The this.handleError() function works too. How can handle this promise error situation?
Just in case handleError() throws, try:
if (!this.isCampaignValid) {
try {
this.handleError()
} catch (e) {
console.error(e);
}
reject()
}
First of all, you don't need to return a promise in an async function. It implicitly returns one, resolving with the value returned by the function or rejecting with the error object if the function throws. Although you could return a promise and JS unpacks it for you, it's unneeded code.
That said, because async returns a promise, you'll have to catch that promise too. Since your first conditional block just throws an error but doesn't catch it, the promise returned by save will reject. You need to handle that rejection.
Here's a simplified version of your code to see where it's happening.
async save(){
if(!this.isCampaignValid){
this.handleError()
// Throwing an error in an async function is equivalent to a reject.
throw new Error('Campaign is not valid') // Here
}
else{
try {
const res = await this.$store.dispatch('updateCampaign')
this.showNotification(res.message, 'success')
} catch (e) {
this.showNotification(error.message, 'error')
}
}
},
// When you call save, catch the error
yourObject.save()
.then(() => {...})
.catch(() => {...})
// If your call is in an async function, you can try-catch as well
try {
await yourObject.save()
} catch(e) {
// It failed.
}
I'm accessing and doing some stuff with a JSON file. If the ajax call fails the error can be caught by .fail(), but when I throw an error inside .done() it doesn't get caught.
function myFunc() {
$.getJSON('data.json')
.done(db => {
/* do stuff with JSON */
if (condition) {
throw Error(message);
}
})
.fail(error => {
throw Error("getJSON request failed.\n" + error);
})
}
try {
myFunc();
} catch (e) {
/* handle error */
}
I understand this is because the function is asynchronous. How can I make sure this error is caught, and that myFunch() finishes executing before ending the try-catch block?
I want to call a util function that might encounter an error. In case of an error the process function should be terminated. The only way to throw an error properly is the callback function.
I would terminate the function by returning, but since I am in the util function, the process function will continue after the util() call.
function util(callback) {
// do something synchronous
if (err) {
// doesn't terminate the process function
// since we are in the util function
return callback("something unexpected happened");
}
}
function process(callback) {
util(callback);
console.log("This should not be printed if an error occurs!");
}
process(function (err) {
if (err) {
// this has to be executed in case of an error
console.log(err);
// terminate the process function somehow?
}
});
Does calling the callback terminate the current function?
No, a callback is just a regular function. It might of course throw an exception (although that is despised).
I want to call a util function that might encounter an error. In case of an error the process function should be terminated.
For that, you need to check in the callback what did happen and act accordingly. You could use process.exit for termination.
function myProcess(callback) {
util(function(err, result) {
if (err) {
callback(err);
} else {
console.log("This should not be printed if an error occurs!");
callback(null, result);
}
});
}
myProcess(function (err) {
if (err) {
// this has to be executed in case of an error
console.log(err);
process.exit(1);
}
});
Notice that promises could simplify this a lot, as they distinguish between success and error callbacks. util would have to return a promise for that:
function util() {
return new Promise(function(resolve, reject) {
// do something asynchronous
if (err)
reject("something unexpected happened");
else
resolve(…);
});
}
function myProcess() {
return util().then(function(res) {
console.log("This should not be printed if an error occurs!");
return res;
});
}
myProcess().catch(function (err) {
// this has to be executed in case of an error
console.log(err);
process.exit(1); // you might not even need this:
throw err; // The node process will by default exit with an unhandled rejection
});
I suggest you make a few changes to your code
function util(callback) {
// do something synchronous
if (err) {
// doesn't terminate the process function
// since we are in the util function
callback("something unexpected happened");
return false;
}
return true;
}
function process(callback) {
if(!util(callback)) return;
console.log("This should not be printed if an error occurs!");
}
This seems like a good time to use a Promise, promises are Javascript's way of forcing a synchronous function. Basically you set it up like this:
var util = new Promise(function(resolve, reject) {
/* do some stuff here */
if (someCondition) {
resolve("With a message");
} else {
reject("with a message");
}
}
function process() {
util.then(function() {
console.log("Won't call if there is an error");
}).catch(function() {
console.log("There was an error, Bob");
});
}
No, you will want to do something like this:
function util(callback) {
// do something synchronous
if (err) {
throw new Error('Something unexpected happened');
}
callback(); // only execute callback if an error did not occur
}
function process(callback) {
try{
util(callback);
console.log("This should not be printed if an error occurs!");
} catch(error){
process(error);
}
}
process(function (err) {
if (err) {
// this has to be executed in case of an error
console.log(err);
process.exit(1)
}
});