Suppose I have an async function
static async update (id, data){
try {
//async function below
_DB.putsomedata()
return true
} catch(e){
//log errors
}
}
And although I don't need the result of _DB.putsomedata(), I still need to know if the update() function finished without errors.
I did some testing and noticed that the result will always return true (thats expected), but in case it fails, the the error is never caught in the catch block, and that raises an unhandled exception.
Can somebody explain the behaviour?
Assuming _DB.putsomedata is an async function, you need to await it. Otherwise its Promise will simply continue in the background, where it eventually fails and produces the error. Your code will have continued on ahead in the meantime and the try..catch block will have long been exited.
putsomedata function is asynchonious, so the return statment in compute just after marking putsomedata as computable (and not launch, as for synchronious function).
putsomedata return probably a promise, which will be resolved after, when cpu will be avaiable.
you can use .promise() .then() .catch() functions
Related
const errorTest = async() => {
const result = await $.get("http://dataa.fixer.io/api/latest?access_key=9790286e305d82fbde77cc1948cf847c&format=1");
return result;
}
try {
errorTest()
}
catch(err) {
console.log("OUTSIDE ERROR!" + err)
}
The URL is intentionally incorrect to throw an error, but the outside catch() it not capturing it. Why?
If I use then() and catch() instead, it works.
errorTest()
.then(val=> console.log(val))
.catch(err=> console.error("ERROR OCCURRED"))
This works, but the try {..} catch() doesn't. Why?
I keep getting the Uncaught (in promise) error.
async function errorTest() { /* ... */ }
try {
errorTest()
}
catch(err) {
console.log("OUTSIDE ERROR!" + err)
}
Because errorTest is async, it will always return a promise and it is never guaranteed to finish execution before the next statement begins: it is asynchronous. errorTest returns, and you exit the try block, very likely before errorTest is fully run. Therefore, your catch block will never fire, because nothing in errorTest would synchronously throw an exception.
Promise rejection and exceptions are two different channels of failure: promise rejection is asynchronous, and exceptions are synchronous. async will kindly convert synchronous exceptions (throw) to asynchronous exceptions (promise rejection), but otherwise these are two entirely different systems.
(I'd previously written that async functions do not begin to run immediately, which was my mistake: As on MDN, async functions do start to run immediately but pause at the first await point, but their thrown errors are converted to promise rejections even if they do happen immediately.)
function errorTest() {
return new Promise(/* ... */); // nothing throws!
}
function errorTestSynchronous() {
throw new Error(/* ... */); // always throws synchronously
}
function errorTestMixed() {
// throws synchronously 50% of the time, rejects 50% of the time,
// and annoys developers 100% of the time
if (Math.random() < 0.5) throw new Error();
return new Promise((resolve, reject) => { reject(); });
}
Here you can see various forms of throwing. The first, errorTest, is exactly equivalent to yours: an async function works as though you've refactored your code into a new Promise. The second, errorTestSynchronous, throws synchronously: it would trigger your catch block, but because it's synchronous, you've lost your chance to react to other asynchronous actions like your $.get call. Finally, errorTestMixed can fail both ways: It can throw, or it can reject the promise.
Since all synchronous errors can be made asynchronous, and all asynchronous code should have .catch() promise chaining for errors anyway, it's rare to need both types of error in the same function and it is usually better style to always use asynchronous errors for async or Promise-returning functions—even if those come via a throw statement in an async function.
As in Ayotunde Ajayi's answer, you can solve this by using await to convert your asynchronous error to appear synchronously, since await will unwrap a Promise failure back into a thrown exception:
// within an async function
try {
await errorTest()
}
catch(err) {
console.log("OUTSIDE ERROR!" + err)
}
But behind the scenes, it will appear exactly as you suggested in your question:
errorTest()
.then(val=> console.log(val))
.catch(err=> console.error("ERROR OCCURRED"))
You need to await errorTest
const callFunction=async()=>{
try{
const result = await errorTest()
}catch(err){
console.log(err)
}
}
callFunction ()
Note that the await errorTest() function has to also be in an async function. That's why I put it inside callFunction ()
Another Option
const errorTest = async() => {
try{
const result = await $.get("http://dataa.fixer.io/api/latest?access_key=9790286e305d82fbde77cc1948cf847c&format=1");
console.log(result)
}catch(err){
console.log(err)
}
}
I think the fundamental misunderstanding here is how the event loop works. Because javascript is single threaded and non-blocking, any asynchronous code is taken out of the normal flow of execution. So your code will call errorTest, and because the call to $.get performs a blocking operation (trying to make a network request) the runtime will skip errorTest (unless you await it, as the other answers have mentioned) and continue executing.
That means the runtime will immediately jump back up to your try/catch, consider no exceptions to have been thrown, and then continue executing statements which come after your try/catch (if any).
Once all your user code has ran and the call stack is empty, the event loop will check if there are any callbacks that need to be ran in the event queue (see diagram below). Chaining .then on your async code is equivalent to defining a callback. If the blocking operation to $.get completed successfully, it would have put your callback in the event queue with the result of errorTest() to be executed.
If, however, it didn't run successfully (it threw an exception), that exception would bubble up, as all exceptions do until they're caught. If you have defined a .catch, that would be a callback to handle the exception and that'll get placed on the event queue to run. If you did not, the exception bubbles up to the event loop itself and results in the error you saw (Uncaught (in promise) error) -- because the exception was never caught.
Remember, your try/catch has long since finished executing and that function doesn't exist anymore as far as the runtime is concerned, so it can't help you handle that exception.
Now if you add an await before errorTest() the runtime doesn't execute any of your other code until $.get completes. In that case your function is still around to catch the exception, which is why it works. But you can only call await in functions themselves that are prefixed with async, which is what the other commenters are indicating.
Diagram is from https://www.educative.io/answers/what-is-an-event-loop-in-javascript. Recommend you check it out as well as https://www.digitalocean.com/community/tutorials/understanding-the-event-loop-callbacks-promises-and-async-await-in-javascript to improve your understanding of these concepts.
I recently ran into a Javascript problem catching errors and thus crashing when exception thrown.
funcReturnPromise().then().catch()
I had to change this to:
try {
funcReturnPromise().then()
} catch (e) {
...
}
Couldn't find a decent explanation for it, any JS wizards available to enlighten a JS peasant?
If funcReturnPromise() can throw synchronously (which functions that return promises should generally never do), then you do have to catch that synchronous exception with try/catch as you discovered when using regular .then().
This is one place where async functions can hep you. For example, if you declare funcReturnPromise as async, then the synchronous exception it throws will automatically become a rejected promise and the caller won't ever be exposed to a synchronous exception.
Or, if the caller (your code here) uses await, then you can catch both sycnhronous exceptions and rejected promises with the same try/catch.
So, for example, you could do this:
async function myFunc()
try {
let result = await funcReturnPromise();
console.log(result);
} catch (e) {
// this catches both a rejected promise AND
// a synchronously thrown exception
console.log(e);
}
}
I am busy working with some code that is responing in an unexpected way (to me). It involves handling Node.js promise exceptions.
I have the following function modified so that all it does is fail
function asynFunc() {
return new Promise(function(res, rej) {
rej("GENERIC ERROR");
});
}
The problem comes in when I am trying to call it and handle this error. If I do the following it works as I expect it to, the function fails and executes the catch which returns, stopping the last console log from executing
async function appStart() {
try {
await asyncFunc();
} catch(log) {
console.log(log);
return;
}
console.log("YOU SHOULD NOT SEE THIS");
}
appStart();
If I write the function as follows though, it does not seem to return, it still executes the last console log regardless of the await
async function appStart() {
await asyncFunc().catch(function(log) {
console.log(log);
return;
});
console.log("YOU SHOULD NOT SEE THIS");
}
If this is doing what I think it's doing then the return is returning from the function inside of the catch and not the appStart function itself, or I'm completely wrong in which case I have no idea why it's not returning.
Is there a way to use the second catch method and still have it return from the calling function?
In the second example, you are not returning from the outside function in the catch, you are returning from the catch callback:
await asyncFunc().catch(function(log) {
console.log(log);// ^
return; // | returns from that function
});
This has the effect of catching the error and moving on and returning a new promise resolving to undefined. There is no way to control the return of the outside function from inside the callback. You need to test the result of the async operation from the outside function, which leaves you with try/catch or explicitly testing the result after the promise resolves.
You're right. It's returning only inside the catch callback, not the outer async function. That's why it exits the catch callback and resolves, and then logs "YOU SHOULD NOT SEE THIS". Generally, it's very unreadable if you mix promise then and catch chaining along with async/await and try/catch. Pick one and stick with it, because mixing them may lead to the inability to catch and handle errors seamlessly.
I have a nodeJS project where I wish to use asynchronous functions. Namely, I'm using the Q library.
I have a function called someFunction(), that I wish to return a promise. With the then -function, I can then check whether the promise was resolved or rejected like so:
someFunction()
.then(
function(results) {
console.log("Success!");
},
function (error) {
console.log("An error occurred, and I would wish to log it for example");
}
);
What I intuitively expect with the function above is, that the error function would catch all possible errors. So if some exception is raised inside the someFunction, I can rest assured, that the error function will be run (the second function after 'then'). But it seems this is not the case.
For example, let's say the someFunction would be defined as so:
function someFunction() {
var deferred = Q.defer();
throw new Error("Can't bar.");
deferred.resolve("success");
}
Now if I call the function someFunction() like done in the upper code block, it won't run the error function. Why is that? Isn't the partial point of the promise Q.deferred to catch errors? Why should I manually reject every error that happens? I know I could set the whole content of someFunction to try/catch clause, and then reject the deferred, but that feels so wrong! There must be a better way, and I know for sure some of you stackoverflowers know it!
With this information, I began to think about where the deferred.reject and deferred.resolve is even meant to be used? Is it even meant to catch exceptions? Should I really just go through all the error cases manually, and call the deferred.reject on them? I'm interested to hear how this should be handled professionally.
Q has specific function for success and error, so use:
deferred.reject("error");
intead of throwing an Exception.
Next thing is that someFunction must return promise to be used as You use it:
function someFunction() {
var deferred = Q.defer();
try{
//some Asynchronous code
deferred.resolve("success");
}catch(e){
deferred.reject(e.message);
}
return deffered.promise; //return promise to use then
}
Because Promises ain't magic. They don't somehow magically catch Errors. They catch them, because they wrap the calls to the callbacks in try..catch-blocks, to convert Errors into rejected Promises.
If you want an Error to be handled by the Promise-chain, well put the function-call into a promise-chain: Q.resolve().then(someFunction).then(...).
Now any synchronous Error occuring in someFunction can be handled in the following then's.
Btw: If you use Q.defer(), and you're not dealing with some callback-style API, you're doing it definitely wrong. Search for the Deferred-antipattern.
it won't run the error function. Why is that?
Because you synchronously threw an exception, instead of returning a promise. Which you never should.
Isn't the partial point of the promise Q.deferred to catch errors?
No. then and catch implicitly catch exceptions in their callbacks, defferreds don't - they're just a (deprecated) API to create promises.
Why should I manually reject every error that happens?
Because asynchronous errors are expected to be passed to callbacks anyway, instead of being thrown.
I know I could set the whole content of someFunction to try/catch clause, and then reject the deferred, but that feels so wrong! There must be a better way!
There is: the Q.Promise constructor, the standard (ES6) promise creation API. It has the benefit of being able to catch synchronous exceptions from the executor function:
function someFunction() {
return new Q.Promise(function(resolve) {
throw new Error("Can't bar.");
resolve("success");
});
}
throwing an error will stop the code from executing (and will close node) unless you catch the error in a try/catch block.
handled errors from requests can be passed to the .catch chain by using deferred.reject(error). code errors and custom thrown errors needs to be handled inside try/catch, which is the right way to handle such errors.
function someFunction() {
var deferred = Q.defer();
deferred.reject("Can't bar.");
// or
try {
throw new Error("Can't bar.");
}
catch(err) {
deferred.reject("Can't bar.");
}
deferred.resolve("success");
}
There are many tutorials on how to use "then" and "catch" while programming with JavaScript Promise. However, all these tutorials seem to miss an important point: returning from a then/catch block to break the Promise chain. Let's start with some synchronous code to illustrate this problem:
try {
someFunction();
} catch (err) {
if (!(err instanceof MyCustomError))
return -1;
}
someOtherFunction();
In essence, I am testing a caught error and if it's not the error I expect I will return to the caller otherwise the program continues. However, this logic will not work with Promise:
Promise.resolve(someFunction).then(function() {
console.log('someFunction should throw error');
return -2;
}).catch(function(err) {
if (err instanceof MyCustomError) {
return -1;
}
}).then(someOtherFunction);
This logic is used for some of my unit tests where I want a function to fail in a certain way. Even if I change the catch to a then block I am still not able to break a series of chained Promises because whatever is returned from the then/catch block will become a Promise that propagates along the chain.
I wonder if Promise is able to achieve this logic; if not, why? It's very strange to me that a Promise chain can never be broken. Thanks!
Edit on 08/16/2015:
According to the answers given so far, a rejected Promise returned by the then block will propagate through the Promise chain and skip all subsequent then blocks until is is caught (handled). This behavior is well understood because it simply mimics the following synchronous code (approach 1):
try {
Function1();
Function2();
Function3();
Function4();
} catch (err) {
// Assuming this err is thrown in Function1; Function2, Function3 and Function4 will not be executed
console.log(err);
}
However, what I was asking is the following scenario in synchronous code (approach 2):
try {
Function1();
} catch(err) {
console.log(err); // Function1's error
return -1; // return immediately
}
try {
Function2();
} catch(err) {
console.log(err);
}
try {
Function3();
} catch(err) {
console.log(err);
}
try {
Function4();
} catch(err) {
console.log(err);
}
I would like to deal with errors raised in different functions differently. It's possible that I catch all the errors in one catch block as illustrated in approach 1. But that way I have to make a big switch statement inside the catch block to differentiate different errors; moreover, if the errors thrown by different functions do not have a common switchable attribute I won't be able to use the switch statement at all; under such a situation, I have to use a separate try/catch block for each function call. Approach 2 sometimes is the only option. Does Promise not support this approach with its then/catch statement?
This can't be achieved with features of the language. However, pattern-based solutions are available.
Here are two solutions.
Rethrow previous error
This pattern is basically sound ...
Promise.resolve()
.then(Function1).catch(errorHandler1)
.then(Function2).catch(errorHandler2)
.then(Function3).catch(errorHandler3)
.then(Function4).catch(errorHandler4)
.catch(finalErrorHandler);
Promise.resolve() is not strictly necessary but allows all the .then().catch() lines to be of the same pattern, and the whole expression is easier on the eye.
... but :
if an errorHandler returns a result, then the chain will progress to the next line's success handler.
if an errorHandler throws, then the chain will progress to the next line's error handler.
The desired jump out of the chain won't happen unless the error handlers are written such that they can distinguish between a previously thrown error and a freshly thrown error. For example :
function errorHandler1(error) {
if (error instanceof MyCustomError) { // <<<<<<< test for previously thrown error
throw error;
} else {
// do errorHandler1 stuff then
// return a result or
// throw new MyCustomError() or
// throw new Error(), new RangeError() etc. or some other type of custom error.
}
}
Now :
if an errorHandler returns a result, then the chain will progress to the next FunctionN.
if an errorHandler throws a MyCustomError, then it will be repeatedly rethrown down the chain and caught by the first error handler that does not conform to the if(error instanceof MyCustomError) protocol (eg a final .catch()).
if an errorHandler throws any other type of error, then the chain will progress to the next catch.
This pattern would be useful if you need the flexibility to skip to end of chain or not, depending on the type of error thrown. Rare circumstances I expect.
DEMO
Insulated Catches
Another solution is to introduce a mechanism to keep each .catch(errorHandlerN) "insulated" such that it will catch only errors arising from its corresponding FunctionN, not from any preceding errors.
This can be achieved by having in the main chain only success handlers, each comprising an anonymous function containing a subchain.
Promise.resolve()
.then(function() { return Function1().catch(errorHandler1); })
.then(function() { return Function2().catch(errorHandler2); })
.then(function() { return Function3().catch(errorHandler3); })
.then(function() { return Function4().catch(errorHandler4); })
.catch(finalErrorHandler);
Here Promise.resolve() plays an important role. Without it, Function1().catch(errorHandler1) would be in the main chain the catch() would not be insulated from the main chain.
Now,
if an errorHandler returns a result, then the chain will progress to the next line.
if an errorHandler throws anything it likes, then the chain will progress directly to the finalErrorHandler.
Use this pattern if you want always to skip to the end of chain regardless of the type of error thrown. A custom error constructor is not required and the error handlers do not need to be written in a special way.
DEMO
Usage cases
Which pattern to choose will determined by the considerations already given but also possibly by the nature of your project team.
One-person team - you write everything and understand the issues - if you are free to choose, then run with your personal preference.
Multi-person team - one person writes the master chain and various others write the functions and their error handlers - if you can, opt for Insulated Catches - with everything under control of the master chain, you don't need to enforce the discipline of writing the error handlers in that certain way.
First off, I see a common mistake in this section of code that could be completely confusing you. This is your sample code block:
Promise.resolve(someFunction()).then(function() {
console.log('someFunction should throw error');
return -2;
}).catch(function(err) {
if (err instanceof MyCustomError) {
return -1;
}
}).then(someOtherFunction()); // <== Issue here
You need pass function references to a .then() handler, not actually call the function and pass their return result. So, this above code should probably be this:
Promise.resolve(someFunction()).then(function() {
console.log('someFunction should throw error');
return -2;
}).catch(function(err) {
if (err instanceof MyCustomError) {
// returning a normal value here will take care of the rejection
// and continue subsequent processing
return -1;
}
}).then(someOtherFunction); // just pass function reference here
Note that I've removed () after the functions in the .then() handler so you are just passing the function reference, not immediately calling the function. This will allow the promise infrastructure to decide whether to call the promise in the future or not. If you were making this mistake, it will totally throw you off for how the promises are working because things will get called regardless.
Three simple rules about catching rejections.
If nobody catches the rejection, it stops the promise chain immediately and the original rejection becomes the final state of the promise. No subsequent handlers are invoked.
If the promise rejection is caught and either nothing is returned or any normal value is returned from the reject handler, then the reject is considered handled and the promise chain continues and subsequent handlers are invoked. Whatever you return from the reject handler becomes the current value of the promise and it as if the reject never happened (except this level of resolve handler was not called - the reject handler was called instead).
If the promise reject is caught and you either throw an error from the reject handler or you return a rejected promise, then all resolve handlers are skipped until the next reject handler in the chain. If there are no reject handlers, then the promise chain is stopped and the newly minted error becomes the final state of the promise.
You can see a couple examples in this jsFiddle where it shows three situations:
Returning a regular value from a reject handler, causes the next .then() resolve handler to be called (e.g. normal processing continues),
Throwing in a reject handler causes normal resolve processing to stop and all resolve handlers are skipped until you get to a reject handler or the end of the chain. This is effective way to stop the chain if an unexpected error is found in a resolve handler (which I think is your question).
Not having a reject handler present causes normal resolve processing to stop and all resolve handlers are skipped until you get to a reject handler or the end of the chain.
There is no built-in functionality to skip the entirety of the remaining chain as you're requesting. However, you could imitate this behavior by throwing a certain error through each catch:
doSomething()
.then(func1).catch(handleError)
.then(func2).catch(handleError)
.then(func3).catch(handleError);
function handleError(reason) {
if (reason instanceof criticalError) {
throw reason;
}
console.info(reason);
}
If any of the catch blocks caught a criticalError they would skip straight to the end and throw the error. Any other error would be console logged and before continuing to the next .then block.
If you can use the newer async await this is pretty simple to implement:
async function myfunc() {
try {
return await anotherAsyncFunction();
} catch {
//do error handling
// can be async or not.
return errorObjct();
}
}
let alwaysGetAValue = await myfunc();
Depending on what technology your using you may need some kind of high level wrapper function to allow for the top level await.