关于错误处理
在开发中不可避免的会出现一些错误或异常,所以我们必须合理的 抛出,捕获,处理这些错误,让程序在我们的预期下正常运行。
抛出错误
对于一些网络请求相关的 Promise 函数,由于网络等各种原因,失败是非常常见的,但是对于这种情况,不能简单的直接抛出错误。
而应该是尝试了一定次数后依然失败后,再将错误抛出。
Promise.retry
所以我们需要实现一个 Promise.retry
,
Promise.retry = (fn, times = 3) => {
new Promise(async (resolve, reject) => {
while (times--) {
try {
const res = await fn()
console.log('执行成功结果是' + res)
break
} catch (err) {
console.log('执行失败:' + err)
}
}
reject('全部执行失败')
}).catch(err => {
console.log(err)
})
}
// 模拟异步函数
function getData() {
const n = Math.random()
return new Promise((resolve, reject) => {
setTimeout(() => {
if (n > 0.7) resolve(n)
else reject(n)
}, 1000)
})
}
//执行
Promise.retry(getData, 3)
控制台执行失败示例输出:
执行失败:0.4864293324880926
执行失败:0.1974050790106614
执行失败:0.595516781548987
全部执行失败
控制台执行成功示例输出:
执行失败:0.5607170295539814
执行成功结果是 0.8403887523046449
演示完后,实际 Promise.retry 可以这样写:
Promise.retry = function (promiseFn, times = 3) {
return new Promise(async (resolve, reject) => {
while (times--) {
try {
const res = await promiseFn()
resolve(res)
break
} catch {}
}
reject('retry failed')
})
}
捕获错误
为了捕获到错误,在代码中就避免不了的要写大量的 try...catch
结构,这样的弊端也显而易见,例如不利于代码阅读。
这篇文章 使用的方案很不错,我个人比较喜欢:
用 try...catch 的写法:
async function run() {
try {
console.log('start')
const result = await UnSuccess()
console.log('result:', result)
} catch (err) {
console.log('发生了错误!')
console.log(err)
}
console.log('end')
}
run()
then-catch 解构赋值:
async function run() {
console.log('start')
const [err, result] = await UnSuccess()
.then(result => [null, result])
.catch(err => [err, null])
if (err) {
console.log('发生了错误!')
console.log(err)
return
}
console.log('result:', result)
console.log('end')
}
run()
还可以对 then-catch 解构赋值 进行封装:
/**
* Promise函数错误处理
* @param {Function} asyncFn 这是一个Promise函数
* @returns {Array} [err,result]
*/
function AsyncHandling(asyncFn) {
return asyncFn()
.then(result => [null, result])
.catch(err => [err, null])
}
async function run() {
console.log('start')
const [err, result] = await AsyncHandling(UnSuccess)
if (err) {
console.log('发生了错误!')
console.log(err)
return
}
console.log('result:', result)
console.log('end')
}
run()
这样代码看起来就十分优雅了。
最后还要注意:
如果在 “计划的(scheduled)”代码中发生异常,例如在 setTimeout
中,则 try...catch
不会捕获到异常:
try {
setTimeout(function () {
noSuchVariable // 脚本将在这里停止运行
}, 1000)
} catch (err) {
alert("won't work")
}
因为这时引擎已经离开了 try...catch
结构。如果要捕获计划的函数中的异常,则需要将 try...catch 放在该函数内。
参考资料:
https://blog.imlete.cn/article/async-await-error-handling.html
https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/387
本文参考并引述了上述链接中的部分相关内容,在这里做出感谢!