try
/catch
存在一个问题是,捕获到的错误只在 catch
后面的块内可见,有些时候这会给编程带来一定的麻烦。例如:
function demo() {
try {
doSomeWork()
} catch (err) {
// err 只在 catch 块内可见
console.error(err)
}
// 执行到这里 err 这个变量已经不存在了
// 但是我们的代码逻辑可能需要在 catch 之后知道是否曾经发生错误
if (!err) {
// 如果没有发生错误才执行这里
}
}
比较容易想到的一个解决方式是:
function demo() {
let err // 把 err 声明提到外面,这样就可以在 try/catch 之后访问到它了
try {
doSomeWork()
} catch (ex) {
err = ex
}
if (!err) {
// 如果没有发生错误才执行这里
}
}
但是这样写比较麻烦。有没有更好的方式?请看下面代码:
function e(fn) {
return function wrapped() {
try {
return [null, fn.apply(this, arguments)]
} catch (err) {
return [err]
}
}
}
function demo() {
// 注意返回格式
const [err, result] = e(doSomeWork)()
if (!err) {
// 如果没有发生错误才执行这里
}
}
是不是简单多了 :D
此外,上面的逻辑还能应用在 async
/await
上面:
function asyncWork(arg1, arg2) {
return new Promise((resolve, reject) => {
if (Math.random() > 0.5) resolve(arg1 + arg2)
else reject('failure')
})
}
async function demo1() {
try {
const result = await asyncWork(2, 3)
return result
} catch (err) {
console.error(err)
}
}
async function demo2() {
const [err, result] = await e(asyncWork)(4, 5)
if (err) {
console.error(err)
} else {
return result
}
}
function e(fn) {
return async function (...args) {
try {
return [null, await fn.apply(this, args)]
} catch (err) {
return [err]
}
}
}
demo1()
demo2()