赞
踩
按键点击无反应、页面元素不展示、页面白屏、接口请求失败,这些都是我们前端不想看到的场景。在计算机程序运行的过程中,也总是会出现各种各样的异常。
什么是异常,异常就是预料之外的事件,往往影响了程序的正确运行。例如下面几种场景:
这些情况都是极其影响用户体验的。对于前端来说,异常虽然不会导致计算机宕机,但是往往会导致用户的操作被阻塞。虽然异常不可完全杜绝,但是我们有充分的理由去理解异常、学习处理异常。
异常处理的重要性是毋庸置疑的。任何有影响力的 Web 应用程序都需要一套完善的异常处理机制,但实际上,通常只有服务端团队会在异常处理机制上投入较大精力。虽然客户端应用程序的异常处理也同样重要,但真正受到重视,还是最近几年的事。作为新世纪的杰出前端开发人员,我们必须理解有哪些异常,当发生异常时我们有哪些手段和工具可以利用。
从根本上来说,异常就是一个数据结构,它存了异常发生时相关信息,比如有错误码、错误信息等。
其中 message 属性是唯一一个能够保证所有浏览器都支持的属性,所以,在考虑浏览器兼容性时,最好还是只使用 message 属性。
执行 JS 期间可能会发生的错误有很多类型。每种错误都有对应的错误类型,而当错误发生的时候就会抛出响应的错误对象。ECMA-262 中定义了下列 7 种错误类型:
Error:错误的基类,其他错误都继承自该类型
EvalError:Eval 函数执行异常
RangeError:数组越界
ReferenceError:尝试引用一个未被定义的变量时,将会抛出此异常
SyntaxError:语法解析不合理
TypeError:类型错误,用来表示值的类型非预期类型时发生的错误
URIError:以一种错误的方式使用全局 URI 处理函数而产生的错误
开发中最常用到的语法就是js了,那么就谈一谈js的异常捕获和处理。
目前前端捕获页面异常的方式主要有两种:try…catch和window.onerror。
try catch
一般来说,使用try…catch可以捕捉前端JavaScript的运行时错误,同时拿到出错的信息,例如错误信息描述、堆栈、行号、列号、具体的出错文件信息等。我们也可以在这个阶段将用户浏览器信息等静态内容一起记录下来,快速地定位问题发生的原因。需要注意的是,try…catch无法捕捉到语法错误,只能在单一的作用域内有效捕获错误信息,如果是异步函数里面的内容,就需要把function函数块内容全部加入到try…catch中执行。
try{ // 单一作用域try...catch可以捕获错误信息并进行处理 console.log(obj); }catch(e){ console.log(e); //处理异常,ReferenceError: obj is not defined } try{ // 不同作用域不能捕获到错误信息 setTimeout(function() { console.log(obj); // 直接报错,不经过catch处理 }, 200); }catch(e){ console.log(e); } // 同一个作用域下能捕获到错误信息 setTimeout(function() { try{ // 当前作用域try...catch可以捕获错误信息并进行处理 console.log(obj); }catch(e){ console.log(e); //处理异常,ReferenceError: obj is not defined } }, 200);
使用try catch能够很好的捕获异常并对应进行相应处理,不至于让页面挂掉,但是其存在一些弊端,比如需要在捕获异常的代码上进行包裹,会导致页面臃肿不堪,不适用于整个项目的异常捕获。
window.onerror
相比try catch来说window.onerror提供了全局监听异常的功能:
window.onerror = function (msg, url, line){
// 可以捕获异步函数中的错误信息并进行处理,提示Script error.
console.log(msg); // 获取错误信息
console.log(url); // 获取出错的文件路径
console.log(line); // 获取错误出错的行数
};
setTimeout(function() {
console.log(obj); // 可以被捕获到,并在onerror中处理
}, 200);
window.onerror的方法可以在任何执行上下文中执行,如果给window对象增加一个错误处理函数,便既能处理捕获错误又能保持代码的优雅性了。window.onerror一般用于捕捉脚本语法错误和运行时错误,可以获得出错的文件信息,如出错信息、出错文件、行号等,当前页面执行的所有JavaScript脚本出错都会被捕捉到。
然而,使用onerror要注意,在不同浏览器中实现函数处理返回的异常对象是不相同的,而且如果报错的JavaScript和HTML不在同一个域名下,错误时window.onerror中的errorMsg全部为script error而不是具体的错误描述信息,
前端代码中,如果你希望浏览直接运行ES6代码,并且使用了Promise,那就不得不重新考虑下Promise的异常捕获了。因为window.onerror并不会去捕获到Promise里面的错误。是的,连script error都没有。就是onerror不会捕获promise里面的错误,应该是早期的浏览器onerror设计没有考虑到Promise直接运行的场景。但借助try-catch封装,我们仍可以做到。
// 如果浏览支持Promise,捕获promise里面then的报错,因为promise里面的错误onerror和try-catch都无法捕获 if (Promise && Promise.prototype.then) { var promiseThen = Promise.prototype.then; Promise.prototype.then = function(resolve, reject) { return promiseThen.call(this, _wrapPromiseFunction(resolve), _wrapPromiseFunction(reject)); } } /** * 输入一个函数,将函数内代码包裹进try-catch执行,then的resolve、reject和普通函数不一样 * * @param {any} fn * @returns 一个新的函数 */ function _wrapPromiseFunction(fn) { // 如果fn是个函数,则直接放到try-catch中运行,否则要将类的方法包裹起来,promise中的fn要返回null,不能返回空函数 if (typeof fn !== 'function') { return null; } return function () { try { return fn.apply(this, arguments); } catch (e) { _errorProcess(e); throw e; } }; }
前端异常捕获与上报是前端异常监控的前提,了解并做好了异常数据的收集和分析才能实现一个完善的错误响应和处理机制,最终达成数据可视化。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。