This question already has answers here:
Using async/await with a forEach loop
(33 answers)
Closed last year.
When I have:
try {
array.forEach(items => {
//do something
//here something is going wrong
})
res.status(200).json({
success: true
})
} catch (err) {
res.status(400).json({
message: err.message
})
}
Error is not catching - I've got 200 response but I can see crashed app and on terminal I have error. But this error is not catched by catch(err) block.
But if I have For of loop I'm getting 400 response.
Erros is the same - in forEach it is not catched and response is ok but in for of loop erros is catched and I have 400 response with error.
Why? Why I can't catch error in forEach and send 400 res by catch block?
Short answer:
This is designed for JS forEach.
Longer one:
Note: There is no way to stop or break a forEach() loop other than by
throwing an exception. If you need such behavior, the forEach() method
is the wrong tool.
From MDN Web Docs Array.prototype.forEach()
BTW, it does not wait for promise as well.
forEach does not wait for promises. Make sure you are aware of the implications while using promises (or async functions) as forEach callback.
In sum,
This probably confuses many JS developers, but in design, this is how JS works.
For avoid the similar issues, try not using forEach, use for or while
Related
This question already has answers here:
Chained promises not passing on rejection
(4 answers)
Closed 2 years ago.
Im new to js and getting hard time understanding the promises, and nested promises. why is it that when my promise return an error, it still load the nested .then(). here is my sample code.
firstFunction()
.then(success(){
//some statement
return secondFunction();
}, error(err){
//logging the err.
})
.then(success(){
//some statement for secondFunction
},error(err){
//logging error for second function
})
when my firstFunction is okay, they work fine, load firstfunction .then, followed by secondFunction.then, but when first function fails, it goes to its :error(err) function, but still executes my code in my secondFunction.then() ?
When you have an error handler and you want the error to continue to propagate, you have to either return a reject promise from the error handler or throw an error. If you don't do either of those, then the error is considered "handled" and the promise state becomes resolved, not rejected.
So, after logging the error, you need to throw the error again.
firstFunction().then(success(){
//some statement
return secondFunction();
}, error(err){
//logging the err.
console.log(err);
throw err; // <== keep the promise rejected
}).then(success(){
//some statement for secondFunction
},error(err){
//logging error for second function
});
FYI, this works just like try/catch. If you catch the error and don't rethrow, then the exception is considered "handled" and normal execution continues. Promises work the same way with their error handlers.
This question already has answers here:
Try catch block is not catching nested callbacks
(2 answers)
Is it possible to catch exceptions thrown in a JavaScript async callback?
(7 answers)
Closed last year.
I am trying to catch an error caused by an async javascript callback function,
try{
setTimeout(()=>{
throw err
console.log("after throw")
}, 1000)
}catch(e){
console.log("caught");
}
But as many of you may know catch block is never executed, so what exactly is happening here?
I know I can achieve similar thing using promises and async/await,
async foo(){
try{
await setTimeoutPromise(1000);
}catch(e){
alert("caught");
}
}
When you use setTimeout, the callback gets pushed into the event loop (moved out of the JS Engine and into the realm of the runtime/browser) and your foo function exits immedeatly.
After the timeout AND once the stack is empty, the event loop will put the callback onto the stack and run it. That's why the try/catch and the callback are independent of each other. That's also why setTimeout(1000) does not mean in a second but not earlier than and somewhat close to one second.
See What the heck is the event loop anyway? | Philip Roberts | JSConf EU
These are two different things.
The first code won't catch the error, since it happens asynchronously, and try...catch will only catch synchronously thrown exceptions.
The second code will catch the error, because await 'synchronize' the code (makes it look and work like it would've been synchronous), and the error thrown only by await: if you haven't been used it, you would get only a rejected promise (You can't really throw anything from an async function!)
To make the first code working, move the try...catch inside the callback:
setTimeout(()=>{
try{
throw err
}catch(e){
console.log('catched')
}
console.log("after throw")
}, 1000)
My question consist of two parts:
Part 1
According to standard ES6 Promise I see that I forced to use catch block everywhere, but it looks like copy/paste and looks weird.
Example:
I have some class which makes request to backend (lets call it API class).
And I have a few requirements for API class using:
1) I need to make requests in different parts of my application with single request errors processing:
// somewhere...
api.getUser().then(... some logic ...);
// somewhere in another module and in another part of app...
api.getUser().then(... some another logic...);
2) I want so 'then' blocks would work ONLY when 'getUsers' succeeded.
3) I don't want to write catch block everywhere I use api.getUsers()
api.getUser()
// I don't want following
.catch(e => {
showAlert('request failed');
})
So I'm trying to implement single error processing inside of the class for all "users requests"
class API {
getUser() {
let promise = makeRequestToGetUser();
promise.catch(e => {
showAlert('request failed');
});
return promise;
}
}
...but if request fails I still forced to use catch block
api.getUser()
.then(... some logic...)
.catch(() => {}) // <- I forced to write it to avoid of “Uncaught (in promise)” warning
... otherwise I'll get “Uncaught (in promise)” warning in console. So I don't know the way of how to avoid of .catch block everywhere I use api instance.
Seems this comes from throwing error in such code:
// This cause "Uncaught error"
Promise.reject('some value').then(() => {});
May be you can say 'just return in your class "catched" promise'.
class API {
getUser() {
return makeRequestToGetUser().catch(e => {
showAlert('request failed');
return ...
});
}
}
...but this contradict to my #2 requirement.
See this demo: https://stackblitz.com/edit/promises-catch-block-question
So my 1st question is how to implement described logic without writing catch block everywhere I use api call?
Part 2
I checked if the same API class implementation with Q library will get the same result and was surprised because I don't get “Uncaught (in promise)” warning. BTW it is more expectable behavior than behavior of native ES6 Promises.
In this page https://promisesaplus.com/implementations I found that Q library is implementation of Promises/A+ spec. But why does it have different behavior?
Does es6 promise respects Promises/A+ spec?
Can anybody explain why these libraries has different behavior, which one is correct, and how implement mentioned logic in case if "ES6 Promises implementation" is correct?
I see that I forced to use catch block everywhere
No, you don't need to do that. Instead, return the promise created by then to the caller (and to that caller's caller, and...). Handle errors at the uppermost level available (for instance, the event handler that started the call sequence).
If that's still too many catchs for you, you can hook the unhandledrejection event and prevent its default:
window.addEventListener('unhandledrejection', event => {
event.preventDefault();
// You can use `event.reason` here for the rejection reason, and
// `event.promise` for the promise that was rejected
console.log(`Suppressed the rejection '${event.reason.message}'`);
});
Promise.reject(new Error("Something went wrong"));
The browser will trigger that event prior to reporting the unhandled rejection in the console.
Node.js supports this as well, on the process object:
process.on('unhandledRejection', error => {
// `error` is the rejection reason
});
Note that you get the reason directly rather than as a property of an event object.
So I don't know the way of how to avoid of .catch block everywhere I use api instance.
Surely the caller of getUser needs to know it failed? I mean, if the answer to that is really "no, they don't" then the event is the way to go, but really the code using api should look like this:
function useTheAPI() {
return getUser()
.then(user => {
// Do something with user
});
}
(or the async equivalent) so that the code calling useTheAPI knows that an error occurred; again, only the top-level needs to actually handle the error.
Can anybody explain why these libraries has different behavior, which one is correct, and how implement mentioned logic in case if "ES6 Promises implementation" is correct?
Both are correct. Reporting unhandled exceptions entirely in userland (where libraries live) is hard-to-impossible to do such that there aren't false positives. JavaScript engines can do it as part of their garbage collection (e.g.: if nothing has a reference to the promise anymore, and it was rejected, and nothing handled that rejection, issue the warning).
I'm trying to find a general way to handle errors on promise chains. In the following snipped I'd like to handle an potential connection-error directly in my connection.js.
connection.js
function getData() {
return fetch(myEndpoint)
.catch(err => handleConnectionError(err)) // redirect to error page or similar
}
app.js
// import connection
connection.getData()
.then(data => handleData(data.foo))
So there are two ways this scenario could play out:
If I catch the error in connection.js without throwing a new one, it will continue the promise chain and handleData() will fail
If I throw an Error again after handling it, the Promise chain wont be executed any further, but then I have an unhandled-promise-rejection error in the console.
So is there actually no better way, than catching and handling the errors everytime I'm using the getData() function somewhere in my app?
The best way to go about this would be to have a final catch to take care of all errors. E.G:
function errorHandler(e) {
if (e instanceof x) {
//handle here
}
}
And then:
fetch(endPoint).then(doSomething).then(doAnotherThing).catch(err => errorHandler(err))
If fetch or any other promise along the chain produces an error, the rest of the then() statements will be skipped and will be catched by the final catch function. From there you will need to make sure that all types of errors that could be thrown by all promises are taken care of.
However, you will need to get rid of the catch in getData as it will cause the rest of the chain to run as usual since the error is taken care of.
Hope that helps
So is there actually no better way, than catching and handling the errors everytime I'm using the getData() function somewhere in my app?
Yes, that's precisely what you should do:
function getData() {
return fetch(myEndpoint)
}
// elsewhere:
connection.getData().then(handleData, handleConnectionError);
You usually don't know whether you always want to "redirect to error page or similar". Maybe at some places in your app, you can handle connection errors by faking response data, and in other places you might want to show an error message instead of triggering a redirect.
Say you have a script that looks like
async function main() {
await somethingThatCanFail()
}
main()
Currently to exit with a non-zero code I'm doing
main()
.then(() => console.log('success message and stuff')
.catch(function(err) {
console.error(err)
process.exit(1)
})
because throw new Error(err) is futile inside of a promise. However, this feels kinda hacky, and I'm wondering if there's a more standard way to do this.
process.exit() is exactly how you should end your process if you want to end it. Nothing "hacky" about that at all.
You properly fielded an error, decided you wanted to abort the process because of that error and ended the process in a documented manner. I would consider an uncaught exception a lot more hacky.
You can output to the console anything you want to for diagnostic purposes before exiting if that's what you thought you might be missing from an unhandled exception.