对于 Javascript 而言,我们面对的仅仅只是异常,异常的出现不会直接导致 JS 引擎崩溃,最多只会使当前执行的任务终止。当前代码块将作为一个任务压入任务队列中,JS 线程会不断地从任务队列中提取任务执行。当任务执行过程中出现异常,且异常没有捕获处理,则会一直沿着调用栈一层层向外抛出,最终终止当前任务的执行。JS 线程会继续从任务队列中提取下一个任务继续执行。
<script>
error
console.log('永远不会执行');
</script>
<script>
console.log('我继续执行')
</script>
异常分类
- 语法错误
- 运行时错误
try-catch
try-catch 只能捕获捉到运行时非异步错误,对于语法错误和异步错误捕捉不到。
try {
error // 未定义变量
} catch(e) {
console.log('我知道错误了');
console.log(e);
}
window.onerror 异常处理
window.onerror 捕获异常能力比 try-catch 稍微强点,无论是异步还是非异步错误,onerror 都能捕获到运行时错误
window.onerror = function (msg, url, row, col, error) {
console.log('我知道错误了');
console.log({
msg, url, row, col, error
})
return true; // 有返回值true 不会暴露在控制台,没有则暴露在控制台
}
setTimeout(() => {
throw new Error("error")
}, 500)
Promise
promise 异步异常直接用 catch 处理
function print() {
return new Promise(function (reslove, reject) {
setTimeout(() => {
console.log(1)
reject('reject')
}, 1000)
})
}
print().catch((err)=>{
console.log(err)
})
async/await
同步形式,使用 try/catch 处理 Promise reject 形式的错误
async function test() {
function print() {
return new Promise(function (reslove, reject) {
setTimeout(() => {
console.log(1)
reject('reject')
}, 1000)
})
}
try {
await print()
} catch (error) {
console.log("trycatch", error)
}
}
test()
reject(new Error("error")) 形式
在 async/await 中会被 try/catch捕获
window.onerror = function (value) {
console.log('onerror', value)
}
async function test() {
function print() {
return new Promise(function (reslove, reject) {
setTimeout(() => {
console.log(1)
reject(new Error("error"))
}, 1000)
})
}
try {
await print()
} catch (error) {
console.log("trycatch", error)
}
}
test()
输出 // trycatch [object error] {}
统一处理 promise 错误
window.addEventListener("unhandledrejection", function (e) {
e.preventDefault()
console.log('我知道 promise 的错误了');
console.log(e.reason);
return true;
});
总结
-
在实际的使用过程中,onerror 主要是来捕获预料之外的错误,而 try-catch 则是用来在可预见情况下监控特定的错误,两者结合使用更加高效。
-
需要注意的是,window.onerror 函数只有在返回 true 的时候,异常才不会向上抛出,否则即使是知道异常的发生控制台还是会显示
-
对于 onerror 这种全局捕获,最好写在所有 JS 脚本的前面,因为你无法保证你写的代码是否出错,如果写在后面,一旦发生错误的话是不会被 onerror 捕获到的。
-
onerror 是无法捕获到网络异常的错误。
-
通过 Promise 可以帮助我们解决异步回调地狱的问题,但是一旦 Promise 实例抛出异常而你没有用 catch 去捕获的话,onerror 或 try-catch 也无能为力,无法捕捉到错误。