let x;
try {
x = ...;
} catch (e) {
return
}
// rest of the code that uses `x`
const y = x + ...;
x
只分配一次,但我必须使用let
代替const
。
另一种方式是:
try {
const x = ...;
// rest of the code that uses `x`
const y = x + ...;
} catch (e) {
return
}
然而,这增加了嵌套并且不清楚什么可以引发错误。
有更好的方法吗?
如果x
失败,我不必关心try
的价值,因为我将在catch
区块中返回。
我也不想将其解析为单独的函数。
答案 0 :(得分:2)
Go功能 - 使用带有三个回调的辅助函数:
function Try(attempt, onSuccess, onFailure) {
try {
var res = attempt();
} catch(err) {
return onFailure(err);
}
return onSuccess(res);
}
这允许你写
return Try(() => …, x => {
// rest of the code that uses `x`
const y = x + …;
}, e => void e);
您还可以使用表示此控制流的数据结构,例如Result
monad(也称为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);
}
}
你可以使用它与上面简单的辅助函数非常相似:
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);
但也有更高级的链接:
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
答案 1 :(得分:1)
每当我遇到这样的事情时,我都会使用一个函数:
a -> b -> ... -> Map k v

注意,堆栈代码段没有正确显示错误。在真正的浏览器控制台中,您将看到如下内容:
巴
TypeError:无法读取属性' baz'未定义的 在constTryCatch((指数):79) 在constTryCatch((指数):69) 在window.onload((index):79)
空
答案 2 :(得分:0)
我会提取简单的函数来进行逻辑和错误处理:
function getXOrHandleError() {
try {
return ...
} catch (e) {
// handle error
return
}
}
const x = getXOrHandleError()
// ...
答案 3 :(得分:0)
使用SanctuaryJS之类的功能标准库,您可以使用Either
monad重写代码,如下所示:
// encaseEither wraps a function so it handles a throw and
// gets the Error object and builds a Left value.
const parseJson = S.encaseEither ( S.I ) ( JSON.parse )
// This will end up in Right, because given JSON
// could be parsed.
const eitherJson = parseJson ( '[ 1, 2, 3 ]' )
// However, this will end up in Left, because given input
// isn't a valid JSON
const eitherJson2 = parseJson ( '{' )
// Sets [ 1, 2, 3 ]
const result = S.fromEither ( [] ) ( eitherJson )
// Sets an empty array
const result2 = S.fromEither ( [] ) ( eitherJson2 )
顺便说一句,如果您正在调用自己的函数,则应尽可能避免使用throw
并使用Maybe
或Either
:
const someFun = x => x < 5 ? S.Nothing : S.Just ( x * 2 )
// Sets Just ( 20 )
const maybeResult = someFun ( 10 )
// Sets Nothing
const maybeResult2 = someFun ( 3 )
const sumFun2 = x => x * 3
// Just ( 30 )
const maybeResult3 = S.map ( somFun2 ) ( maybeResult )
// Nothing
const maybeResult4 = S.map ( someFun2 ) ( maybeResult2 )
// Get maybeResult3 or output a default
// So it sets 30
const result3 = S.fromMaybe ( 0 ) ( maybeResult3 )
// Get maybeResult3 or output a default
// So it sets 0
const result4 = S.fromMaybe ( 0 ) ( maybeResult4 )
我会完全避免例外。对于来自库和框架的那些函数,我会将它们全部包装以使用monad来表达效果。