js 各种错误处理

254 阅读2分钟

对于 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 也无能为力,无法捕捉到错误。