How can Javascript duplicate the four-part try
-catch
-else
-finally
execution model that other languages support?
A
Javascript does not have the syntax to support the no-exception scenario. The best workaround is nested try
statements, similar to the "legacy" technique from PEP 341
// A pretty-good try/catch/else/finally implementation.
try {
var success = true;
try {
protected_code();
} catch(e) {
success = false;
handler_code({"exception_was": e});
}
if(success) {
else_code();
}
} finally {
this_always_runs();
}
Besides readability, the only problem is the success
variable. If protected_code
sets window.success = false
, this will not work. A less readable but safer way uses a function namespace:
// A try/catch/else/finally implementation without changing variable bindings.
try {
(function() {
var success = true;
try {
protected_code();
} catch(e) {
success = false;
handler_code({"exception_was": e});
}
if(success) {
else_code();
}
})();
} finally {
this_always_runs();
}
I know the question is old and answers has already given but I think that my answer is the simplest to get an "else" in javascripts try-catch-block.
var error = null;
try {
/*Protected-block*/
} catch ( catchedError ) {
error = catchedError; //necessary to make it available in finally-block
} finally {
if ( error ) {
/*Handler-block*/
/*e.g. console.log( 'error: ' + error.message );*/
} else {
/*Else-block*/
}
/*Final-block*/
}
I know this is old, but here is a pure syntax solution, which I think is the proper way to go:
try {
// Protected-block
try {
// Else-block
} catch (e) {
// Else-handler-block
}
} catch(e) {
// Handler-block
} finally {
// Final-block
}
The code in Protected-block is executed. If the code throws an error, Handler-block is executed; If no error is thrown, Else-block is executed.
No matter what happened previously, Final-block is executed once the code block is complete and any thrown errors handled. Even if there’s an error in Handler-block or Else-block, the code in Final-block is still run.
If an error is thrown in the Else-block it is not handled by the Handler-block but instead by the Else-handler-block
And if you know that the Else-block will not throw:
try {
// Protected-block
// Else-block
} catch(e) {
// Handler-block
} finally {
// Final-block
}
Moral of the story, don't be afraid to indent ;)
Note: this works only if the Else-handler-block never throws.
Extending the idea of jhs a little, the whole concept could be put inside a function, to provide even more readability:
var try_catch_else_finally = function(protected_code, handler_code, else_code, finally_code) {
try {
var success = true;
try {
protected_code();
} catch(e) {
success = false;
handler_code({"exception_was": e});
}
if(success) {
else_code();
}
} finally {
finally_code();
}
};
Then we can use it like this (very similar to the python way):
try_catch_else_finally(function() {
// protected block
}, function() {
// handler block
}, function() {
// else block
}, function() {
// final-block
});
Here's another solution if the problem is the common one of not wanting the error callback to be called if there is an uncaught error thrown by the first callback. ... i.e. conceptually you want ...
try {
//do block
cb(null, result);
} catch(err) {
// err report
cb(err)
}
But an error in the success cb causes the problem of cb getting called a second time. So instead I've started using
try {
//do block
try {
cb(null, result);
} catch(err) {
// report uncaught error
}
} catch(err) {
// err report
cb(err)
}
which is a variant on @cbarrick's solution.