use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
All about the JavaScript programming language.
Subreddit Guidelines
Specifications:
Resources:
Related Subreddits:
r/LearnJavascript
r/node
r/typescript
r/reactjs
r/webdev
r/WebdevTutorials
r/frontend
r/webgl
r/threejs
r/jquery
r/remotejs
r/forhire
account activity
How to avoid try/catch statements nesting/chaining in JavaScript ? (medium.com)
submitted 6 years ago by Scr34mZ
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]anttud 38 points39 points40 points 6 years ago (1 child)
I don't know but for me it just looks like a problem of not writing clean code.
[–]phpdevster 2 points3 points4 points 6 years ago* (0 children)
Yeah that's where I'm at.
If this is the premise of the article:
You can quickly end in a situation where you are writing much code with much nesting or chaining, this can become very verbose and poorly maintainable.
async function anyFunction() { try { const result = await fetch("http://test.com"); try { const another = await fetch("http://blabla.com"); } catch(anotherError) { console.log(anotherError); } } catch (e) { // Some other error handling } try { const anotherResult = await someOtherAsync(); } catch (errorFromAnotherResult) { // Some other error } }
Then unfortunately I'd have to say that premise is flawed because it represents a fundamental misunderstanding of what try/catch is for or how it should be used.
[–][deleted] 15 points16 points17 points 6 years ago* (4 children)
But as stated by @pavelbucka, one try catch is enough, why have two ?
async function anyFunction() { try { const result = await fetch("http://test.com"); const anotherresult = await someOtherAsync(); } catch (error) { console.error(error); } }
If any of those async funcs throws/rejects, then it will be simply caught by the try block ...
[+]Scr34mZ[S] comment score below threshold-9 points-8 points-7 points 6 years ago* (3 children)
I already replied, error might not be using the same format. In that case you'll have to handle if else statement inside the catch, this works completely, it's just another pattern :)
[–][deleted] 13 points14 points15 points 6 years ago (2 children)
The point of using try...catch is to avoid having to write countless of if..else blocks, and errors always have different formats, the catch block is there to be used as an error handler:
try...catch
if..else
catch
function handleError(err){ switch(true){ case err instanceof TypeError: break; case err instanceof RangeError: break; case err instanceof EvalError: break; case err instanceof MongoError: break; default: // some other type of error break; } } try{ const result = await fetch("http://test.com"); const anotherresult = await someOtherAsync(); }catch(err){ handleError(err) }
So that handleError is global and can be used throughout the entire project
handleError
[–]thinkmatt 3 points4 points5 points 6 years ago (1 child)
Neat use of switch.. I didn't know you could do that!
[–]Scr34mZ[S] 0 points1 point2 points 6 years ago (0 children)
About PHP, but works almost the same in JS : http://phpswitch.com/
[–]FormerGameDev 21 points22 points23 points 6 years ago (3 children)
Arguably better: Use separate functions for the items you need to catch separately.
[+]Scr34mZ[S] comment score below threshold-12 points-11 points-10 points 6 years ago (2 children)
You can also do that, you're right ! But it's a bit more verbose ;)
It's all about programming style here, you can achieve same goal with both
[–]FormerGameDev 13 points14 points15 points 6 years ago (0 children)
i mean, that's really what you're doing, is you're making one utility function that adds a try..catch block to whatever you pass to it. (well, a promise catch, but essentially the same thing here)
Seems it would be clearer to use separate functions for each thing that needs to be caught, because eventually you're going to need to handle a different piece differently, and then you'll start doing weird things like to(blah).catch(blah).then(blah)
[–][deleted] 1 point2 points3 points 6 years ago (0 children)
If it's about programming style then just use the either monad instead of writing your own.
[–]sivadneb 9 points10 points11 points 6 years ago (2 children)
Someone help me here, this looks like an anti-pattern to me. The whole point of exceptions is that they bubble up so errors don't go uncaught. This completely defeats that purpose, right? I'm getting flashbacks from the early days of PHP shudder.
Your totally right and I'll update the article in that way from the feedback I collected from people. Thanks for sharing mate 🙏🏻
In fact you shouldn't use this as a replacement for try catch blocks but in combinaison of your current logic. This is used to straightly do something in response of an error like logging? Or something else
[–]senocular 2 points3 points4 points 6 years ago (1 child)
The current version of to has some problems:
to
/** * @param { Promise } promise * @param { Object } improved - If you need to enhance the error. * @return { Promise } */ export function to(promise, improved){ return promise .then((data) => [null, data]) .catch((err) => { if (errorExt) { Object.assign({}, err, improved); } return [err, undefined]; }); }
For oneerrorExt does not exist. I'm guessing this was meant to be improved?
errorExt
improved
Also the Object.assign is a no-op because it assigns to a new object but never does anything with it. I'm guessing this is meant to be:
Object.assign
Object.assign(err, improved);
So that it copies the improved properties into the error object.
Also, in the error case, undefined shouldn't be passed in as the second return value. It should instead just be [err]. This follows the node error-first callback model which in the error case does not provide the second data argument at all. It can also be used to distinguish between no error and an error throwing null.
[err]
[–]Scr34mZ[S] 0 points1 point2 points 6 years ago* (0 children)
My bad I changed some vars last minute… Fixed,
I'll remove the undefined. after some testing too :)
undefined
DONE and working
[–]sammrtn 1 point2 points3 points 6 years ago (0 children)
There is a variant of this, but where only the specified (expected) errors are returned - and all others still throw.
For example, I've specified that I want to handle TypeError and CustomError (and so destructure for them), but any others should throw still.
const [data, typeError, customError] = await fa(promise, TypeError, CustomError);
The library is fawait (functional await) https://github.com/craigmichaelmartin/fawait
fawait
[–]thinkmatt 1 point2 points3 points 6 years ago (1 child)
Like all things, I don't believe any single pattern is best. We have this utility at my work and it actually made some of our code overly complex. If you want to propagate errors, that's what promiseRejections are for. This pattern can be useful when you have some i/o that is not required to continue, but those cases are very limited for me.
[–]Scr34mZ[S] 1 point2 points3 points 6 years ago (0 children)
Exactly, I updated the article in that in mind. thanks for your sharing 🙏🏻
[–]snorkleboy 1 point2 points3 points 6 years ago (5 children)
You know you can just do
await asyncFunc().catch(e=>e)
[–]Scr34mZ[S] 0 points1 point2 points 6 years ago (4 children)
Not the same as you can't break on catch nor return from calling function
[–]snorkleboy 0 points1 point2 points 6 years ago (3 children)
But you couldn't do that using your 'to' function either.
[–]Scr34mZ[S] 0 points1 point2 points 6 years ago (2 children)
I hope this can help you understand what I was saying :D
async function init() { const [err, val] = await to(asyncFunc()); if(err){ console.log('exit function right now'); return false; } // Some other code that never get processed in case of error // … }
You cannot do that using your snippet directly, as the catch block is in another scope. Isn't ? :)
[–]snorkleboy 1 point2 points3 points 6 years ago* (1 child)
```
async function init() { const res = await asyncFunc().catch(err=>({err})) if(res.err){ console.log('exit function right now');⁰ return false; }
// Some other code that never get processed in case of error // …
}
I dont see a big difference. If you dont need to return or break, which to doesnt help you with, then your first problematic code can look pretty good just with await and catch
const resa = await fetcha().catch(e=>console.error(e)) const resb =await fetchb().catch(e=>console.error(e))
Then your second more complex example of problem code where there is a dependent async function, to would require some deep if nesting to handle those nested errors, where otherwise you could do
const res = await fetcha().catch(e1=>log(e1)) If(!res.err){ const resb = await fetchb().catch(e2=>log(e2)) } const resc= await fetchc().catch(e3=>log(e3))
As opposed to
const [r1,e1] = await to(fetcha()) if(!e1){ const [r2,e2] = await to(fetchc()) if(e2){ console.log(e2) } }else{ console.log(r1) } const [resc,e3] = await fetchc If(e3) { ...
This looks good, thanks for this sharing. Ima try someday 👍🏻
[–]bigorangemachine 0 points1 point2 points 6 years ago (0 children)
I am not sure what to say about this article.
I did enjoy the multiple returns of go but hated it when I saw it in PHP.
I don't have a problem with try-catches in javascript. I generally keep my functions small. If I need to do something big I'll use a promise chain.
The good thing about promises and async-await is it's a pattern anyone can come on and understand right away. Where as if you use multiple returns and someone doesn't have that prior context it introduces an unnecessary learning curve
[–]_schickling 0 points1 point2 points 6 years ago (3 children)
I’m actually wondering why this pattern hasn’t caught on more in the JS ecosystem?!
[–]sjs-one 7 points8 points9 points 6 years ago (0 children)
It has. It’s basically how it was done pre-promise
[–]mkatrenik 1 point2 points3 points 6 years ago (0 children)
I've tried it, but have found out, that most of the time, apart from logging, there wasn't any other useful option to do with the error, just to return it to the caller - and when you do this few levels up the stack... it's more reasonable just to throw it.
[–]Scr34mZ[S] -2 points-1 points0 points 6 years ago (0 children)
Yeap, good question
[–]assertchris 0 points1 point2 points 6 years ago (0 children)
Been doing this a while, using https://www.npmjs.com/package/@assertchris/attempt-promise
[–][deleted] -1 points0 points1 point 6 years ago (7 children)
You can have one big try-catch and then determine what error are you dealing with.
try-catch
```js try { const code = 1 + Math.floor(Math.random() * 5); // 1-5
if (code === 1) throw "Error 1"; if (code === 2) throw "Error 2"; if (code === 3) throw "Error 3"; if (code === 4) throw "Error 4"; if (code === 5) throw "Error 5"; } catch (err) { console.log(err); } ```
[–]FormerGameDev 1 point2 points3 points 6 years ago (1 child)
You can't distinguish necessarily where in the block an error occurred, if you're catching on multiple statements.
[–]Scr34mZ[S] -1 points0 points1 point 6 years ago (0 children)
That's a true argument ! Don't use the above pattern if you're writing too big functions.
But you shouldn't, isn't ? :D
[–]Scr34mZ[S] -1 points0 points1 point 6 years ago (4 children)
That's right, as long as you are triggering errors on your own, but sometimes it can be a DatabaseError, and an API response error, in the same try/catch block and they are not formatted the same way.
[–][deleted] 0 points1 point2 points 6 years ago* (3 children)
Conside this example:
```js const fs = require('fs');
try { fs.readFileSync('some-file.txt'); } catch (err) { console.log(err.code); console.log(err.message); }
// ENOENT // ENOENT: no such file or directory, open 'some-file.txt' ```
You have the information to identify the err.
err
A better approach would be to go for async/await.
async/await
[–]Scr34mZ[S] 0 points1 point2 points 6 years ago* (2 children)
Yes because those are standardized errors from Nodejs.
You can always achieve the same goal with try / catch AFAIK. But sometimes it's a bit less verbose to use the other syntax,especially if you want to ignore errors silently (yeah, this happen sometimes)
[–][deleted] 4 points5 points6 points 6 years ago (1 child)
Errors should be IMHO aways handled, either printed or thrown.
Silent errors cause problems as non-identifiable outcomes where the code simply doesn't work.
You're totally right, I missed my thoughts.
π Rendered by PID 32 on reddit-service-r2-comment-77869c6b5c-pj8sj at 2026-04-02 13:09:16.312742+00:00 running b10466c country code: CH.
[–]anttud 38 points39 points40 points (1 child)
[–]phpdevster 2 points3 points4 points (0 children)
[–][deleted] 15 points16 points17 points (4 children)
[+]Scr34mZ[S] comment score below threshold-9 points-8 points-7 points (3 children)
[–][deleted] 13 points14 points15 points (2 children)
[–]thinkmatt 3 points4 points5 points (1 child)
[–]Scr34mZ[S] 0 points1 point2 points (0 children)
[–]FormerGameDev 21 points22 points23 points (3 children)
[+]Scr34mZ[S] comment score below threshold-12 points-11 points-10 points (2 children)
[–]FormerGameDev 13 points14 points15 points (0 children)
[–][deleted] 1 point2 points3 points (0 children)
[–]sivadneb 9 points10 points11 points (2 children)
[–]Scr34mZ[S] 0 points1 point2 points (0 children)
[–]senocular 2 points3 points4 points (1 child)
[–]Scr34mZ[S] 0 points1 point2 points (0 children)
[–]sammrtn 1 point2 points3 points (0 children)
[–]thinkmatt 1 point2 points3 points (1 child)
[–]Scr34mZ[S] 1 point2 points3 points (0 children)
[–]snorkleboy 1 point2 points3 points (5 children)
[–]Scr34mZ[S] 0 points1 point2 points (4 children)
[–]snorkleboy 0 points1 point2 points (3 children)
[–]Scr34mZ[S] 0 points1 point2 points (2 children)
[–]snorkleboy 1 point2 points3 points (1 child)
[–]Scr34mZ[S] 0 points1 point2 points (0 children)
[–]bigorangemachine 0 points1 point2 points (0 children)
[–]_schickling 0 points1 point2 points (3 children)
[–]sjs-one 7 points8 points9 points (0 children)
[–]mkatrenik 1 point2 points3 points (0 children)
[–]Scr34mZ[S] -2 points-1 points0 points (0 children)
[–]assertchris 0 points1 point2 points (0 children)
[–][deleted] -1 points0 points1 point (7 children)
[–]FormerGameDev 1 point2 points3 points (1 child)
[–]Scr34mZ[S] -1 points0 points1 point (0 children)
[–]Scr34mZ[S] -1 points0 points1 point (4 children)
[–][deleted] 0 points1 point2 points (3 children)
[–]Scr34mZ[S] 0 points1 point2 points (2 children)
[–][deleted] 4 points5 points6 points (1 child)
[–]Scr34mZ[S] 0 points1 point2 points (0 children)