let x;
try {
x = ...;
} catch (e) {
return
}
// rest of the code that uses `x`
const y = x + ...;
x
is assigned exactly once, yet I have to use let
instead of const
.
The other way would be:
try {
const x = ...;
// rest of the code that uses `x`
const y = x + ...;
} catch (e) {
return
}
However, this increases nesting and makes it unclear what can throw an error.
Is there a better way?
I don't have to care about the value of x
if the try
fails, as I'll be returning in the catch
block.
I also don't want to extract it out to separate functions.
Place any code statements that might raise or throw an exception in a try block, and place statements used to handle the exception or exceptions in one or more catch blocks below the try block. Each catch block includes the exception type and can contain additional statements needed to handle that exception type.
Yes, we can declare a try-catch block within another try-catch block, this is called nested try-catch block.
The try statement allows you to define a block of code to be tested for errors while it is being executed. The catch statement allows you to define a block of code to be executed, if an error occurs in the try block.
Variables in try block So, if you declare a variable in try block, (for that matter in any block) it will be local to that particular block, the life time of the variable expires after the execution of the block. Therefore, you cannot access any variable declared in a block, outside it.
Whenever I run across something like this, I use a function:
function constTryCatch(valueFn, catchFn) {
try {
return valueFn();
} catch (e) {
if (catchFn) catchFn(e);
return null;
}
}
const obj = { foo: 'bar' };
const x = constTryCatch(() => obj.foo);
console.log(x);
const y = constTryCatch(() => obj.foo.bar.baz, (e) => console.log(e));
console.log(y);
// example, if the rest of the block depends on `y` being truthy:
// if (!y) return;
Note, the stack snippet doesn't display the error properly. In the real browser console, you'll see something like this:
bar
TypeError: Cannot read property 'baz' of undefined at constTryCatch ((index):79) at constTryCatch ((index):69) at window.onload ((index):79)
null
Go functional - use a helper function with three callbacks:
function Try(attempt, onSuccess, onFailure) {
try {
var res = attempt();
} catch(err) {
return onFailure(err);
}
return onSuccess(res);
}
This allows you to write
return Try(() => …, x => {
// rest of the code that uses `x`
const y = x + …;
}, e => void e);
You can also make use of a data structure representing this control flow, like the Result
monad (also known as the Either
monad):
class Result {
constructor(go) {
this.go = go;
}
static Ok(v) {
return new this((onSuccess, _) => onSuccess(v));
}
static Err(r) {
return new this((_, onFailure) => onFailure(v));
}
map(f) {
return this.go(v => Result.Ok(f(v)), r => Result.Err(r));
}
chain(f) {
return this.go(v => f(v), r => Result.Err(r));
}
unwrap() {
return this.go(v => v, r => { throw r; });
}
}
function Try(attempt) {
try {
var res = attempt();
return Result.Ok(res);
} catch(e) {
return Result.Err(e);
}
}
You could use it very similar to the above simple helper function:
return Try(() =>
… // exceptions in here are caught
).go(x => {
// rest of the code that uses `x` - exceptions are not caught
const y = x + …;
}, e => void e);
But also with more advanced chaining:
return Try(() =>
… // exceptions in here are caught
).chain(x =>
Try(() =>
x + … // exceptions in here are caught as well
)
).map(y =>
… // exceptions in here are not caught
).unwrap(); // any caught exceptions are re-thrown
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With