您好!
欢迎来到京东云开发者社区
登录
首页
博文
课程
大赛
工具
用户中心
开源
首页
博文
课程
大赛
工具
开源
更多
用户中心
开发者社区
>
博文
>
javascript错误处理浅析
分享
打开微信扫码分享
点击前往QQ分享
点击前往微博分享
点击复制链接
javascript错误处理浅析
自猿其说Tech
2021-12-13
IP归属:未知
28360浏览
前端
### 1 前言 在一个阳光明媚的下午,小A上线了一个功能,运行了一段时间没有发现错误,小A安心的回家了,到了晚上线上用户报系统无法登录,由于不能说清楚问题在哪又不想大范围影响线上用户,leader一声令下“回滚”,小B开始回滚,在大家满心期待的时候,嗯~还是不能登录,后端继续回滚,还是不行~,到此只能打开编辑器,调试线上代码,最后发现是别的系统出了问题,于是leader开始联系别的系统,于是线上问题解决了。。。鉴于每次出现线上问题小A、小B等同学都无从下手,只能通过调试线上代码查找问题,所以想增加异常监控及监控报警,方便研发人员快速定位问题及解决问题,于是小A开始了后续探索...... 本文主要研究错误的基本类型及如何捕获错误。报警及监控会继续增加~ ### 2 javascript错误类型 #### 2.1 Error ##### 2.1.1 Error方法与属性 是基础类型,其他几种错误类型都是继承此类型,因此,所有错误类型都共享相同的属性,浏览器很少抛出Error了类型的错误,该类型主要是开发人员抛出自定义错误 Error包含以下属性 - Error.prototype.message - 错误信息 - Error.prototype.name - 错误名 - Error.prototype.toString() - 表示错误对象的描述信息 ##### 2.1.2 使用 ```javascript const error = new Error('出错了'); console.log(error) console.log('error:' + error) console.log('message:' + error.message) console.log('name:' + error.name) ``` ![](//img1.jcloudcs.com/developer.jdcloud.com/0f2d5557-320e-48eb-a70c-d49ff856f70620211213143822.png) #### 2.2 InternalError InternalError 类型的错误会在底层 JavaScript 引擎抛出异常时由浏览器抛出(不同浏览器的报错可能有差异)。例如,递归过多导 致了栈溢出。这个类型并不是代码中通常要处理的错误,如果真发生了这种错误,很可能代码哪里弄错 了或者有危险了 ```javascript function loop(x) { if (x >= 1000000000000) return; // do stuff loop(x + 1); } loop(0); ``` Firefox报错 ![](//img1.jcloudcs.com/developer.jdcloud.com/0adeea53-deaf-4be6-9902-8cb45ad46f0020211213143907.png) Chrome报错 ![](//img1.jcloudcs.com/developer.jdcloud.com/15717fd7-9015-42d0-88bc-fd28c3f2b7c020211213143917.png) #### 2.3 EvalError EvalError 类型的错误会在使用 eval()函数发生异常时抛出 ,基本上,只要不把 eval()当 成函数调用就会报告该错误 ,实践中,浏览器不会总抛出 EvalError,但是代码中一般不大可能这样使用,所以几乎遇不到这种错误 ```javascript new eval(); ``` ![](//img1.jcloudcs.com/developer.jdcloud.com/c2e622f6-2c9a-467c-898a-5dce0d82d67220211213143950.png) #### 2.4 RangeError RangeError 错误会在数值越界时抛出 ```javascript let items = new Array(-1); let items2 = new Array(Number.MAX_VALUE) ``` ![](//img1.jcloudcs.com/developer.jdcloud.com/ed9b08fc-2eeb-4f04-bdb4-8c24950c877e20211213144016.png) #### 2.5 ReferenceError ReferenceError 会在找不到对象时发生 。这种错误经常是由访问不存在的变量而导致的 ```javascript console.log(a) ``` ![](//img1.jcloudcs.com/developer.jdcloud.com/f372e9e3-a7cc-4ecb-a18e-2e0dc257e9f220211213144050.png) #### 2.6 SyntaxError 语法错误往往是代码书写错误,遇到此类错误首先检查js 代码是否出错,如果没有就检查 (), {}, <>,;等这些是否出现错误 ```javascript console.log(a ++ b) ``` ![](//img1.jcloudcs.com/developer.jdcloud.com/a45b527e-31c3-4bbd-aa13-c542f72f063020211213144117.png) #### 2.7 TypeError TypeError 在 JavaScript 中很常见,主要发生在变量不是预期类型,或者访问不存在的方法时。很 多原因可能导致这种错误,尤其是在使用类型特定的操作而变量类型不对时 ```javascript let o = new 10; console.log("name" in true); Function.prototype.toString.call("name"); ``` ![](//img1.jcloudcs.com/developer.jdcloud.com/0816247d-4e16-4cc5-beee-1d0c6234c10120211213144142.png) #### 2.8 URIError URIError,只会在使用 URI编码 时发生 ```javascript decodeURIComponent('%') ``` ![](//img1.jcloudcs.com/developer.jdcloud.com/0c05eafe-cc1f-4f52-a849-97e32f512ca920211213144236.png) ### 3 抛出错误 #### 3.1 throw throw 操作符,用于在任何时候抛出自定义错误。throw 操 作符必须有一个值,但值的类型不限。下面这些代码都是有效的 ,使用 throw 操作符时,代码立即停止执行,除非 try/catch 语句捕获了抛出的值。 ```javascript throw 12345 throw "Hello world!" throw true; throw { name: "zyj" } ``` 自定义错误常用的错误类型是 Error、RangeError、ReferenceError 和 TypeError ```javascript throw new Error('函数异常') throw new TypeError('order参数为数值') throw new ReferenceError('找不到对象') throw new RangeError('不可用的数组长度') ``` #### 3.2 自定义错误类型 自定义错误类型继承Error会被浏览器当成其他内置错误类型,自定义错误类型有助于捕获错误时更准确的区分错误 ```javascript try { class CustomError extends Error { constructor(message, code) { super() this.name = 'CustomError' this.message = message this.code = code } } // 抛出错误 throw new CustomError("my message", '测试code') } catch(ex) { console.log(ex, ex.code) } ``` ![](//img1.jcloudcs.com/developer.jdcloud.com/a793c0d3-c1b6-4e42-8a0c-101c7daf710120211213144337.png) #### 3.3 何时抛出错误 在出现已知函数无法正确执行的情况下就应该抛出错误,浏览器会在指定环境下抛出错误,但是错误信息往往模棱两可。在遇到上千行代码时找问题就会很困难。 ```javascript function process(values){ for (let value of values){ // } } process(111) ``` ![](//img1.jcloudcs.com/developer.jdcloud.com/0f715b94-39f7-4315-8421-ff0991a8836620211213144403.png) 上面的错误如果代码量很大,查找起来就会非常困难,如果我们用适当的抛出错误信息将会提高代码的可维护性,如上面的代码重写下 ```javascript function process(values){ if (!(values instanceof Array)){ throw new Error("process(): 参数必须为可枚举类型"); } for (let value of values){ // } } process(111) ``` ![](//img1.jcloudcs.com/developer.jdcloud.com/11d7e242-151b-4e37-83e0-ee9ff4cd937a20211213144430.png) #### 3.4 抛出错误与捕获错误 一个常见的问题是何时抛出错误何时捕获错误,一般来说,错误要在架构的底层抛出,如果你在编写一个可以能用于多个应用的javascript库,或者在应用中很多地方都会用到的函数,那么就应该认真考虑抛出带有详细信息的错误。至于捕获错误,捕获错误的目的是阻止浏览器以其默认方式响应,应该只有在确切知道接下来该做什么的时候捕获错误 关于try...catch 详细文章可以查看: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/try...catch ### 4 异常捕获方法 #### 4.1 try/catch 1)js 抛出错误后,会导致当前执行任务停止,异常后面的代码不会执行 ```javascript try { console.log(text) console.log('111') // 上面抛出错误后,此处不会继续执行 } catch (ex) { console.log('错误:', ex) } ``` ![](//img1.jcloudcs.com/developer.jdcloud.com/c74d9233-b205-4909-bff7-8f582669a90020211213144516.png) 2)try/catch 不能捕获语法错误异常,不能捕获异步异常,只能捕获同步发生的异常 以下在settimeout中手动抛出错误,发现并没有被catch捕获 ```javascript try { console.log('测试异步捕获') setTimeout(() => { throw Error('报错啦!') }, 0) } catch (ex) { console.log('错误:', ex) } ``` ![](//img1.jcloudcs.com/developer.jdcloud.com/7d8f9b52-f122-4e93-a9c1-eceff0882c9d20211213144542.png) 3)try/catch 不能捕获promise异常 ```javascript try { const p = new Promise((resolve, reject) => { reject(new Error('promise reject')) }) p } catch(ex) { console.log(ex, 'promise error') } ``` ![](//img1.jcloudcs.com/developer.jdcloud.com/a5ddbdc6-2213-4125-b5fc-da99e9e0b27520211213144616.png) 4)try/catch 可以捕获async/await异常 ```javascript function testAsync () { return new Promise((resolve, reject) => { reject('Promise reject!!!') }) } async function fn() { try { await testAsync() } catch(ex) { console.log(ex, 'testAsync error') } } fn() ``` ![](//img1.jcloudcs.com/developer.jdcloud.com/3ab39419-3cc5-4d12-89f3-67138fd6f83f20211213144652.png) #### 4.2 全局监控JS异常: window.onerror ```javascript /** * @param {String} message 错误详细信息 * @param {String} resource 错误文件 * @param {Number} row 错误行号 * @param {Number} col 错误列号 * @param {Object} error 错误详细信息error对象 * */ window.onerror = function(message,resource,row,col,error) { console.log('捕获到错误信息'); console.log({message,resource,row,col,error}); } aaaa ``` ![](//img1.jcloudcs.com/developer.jdcloud.com/d497fc79-a8df-42e3-afb7-c2d206362b3220211213144723.png) - window.onerror 函数主要用来捕获意料之外的错误,而try/catch 主要是捕获可预见情况下的错误,window.onerror 最好放在代码的最前面,否则可能不会执行 - window.onerror 可以捕获异步(哪些异步)、同步错误,但是不能捕获语法、网络请求错误 ```javascript <body> <img src="./aaa.png" /> </body> <script> /** * @param {String} message 错误信息 * @param {String} resource 出错文件 * @param {Number} row 行号 * @param {Number} col 列号 * @param {Object} error 错误详细信息error对象 * */ window.onerror = function(message,resource,row,col,error) { console.log('捕获到错误信息'); console.log({message,resource,row,col,error}); } </script> ``` ![](//img1.jcloudcs.com/developer.jdcloud.com/50a24dc4-36f2-4778-a605-e8fbb996247a20211213144757.png) #### 4.3 全局监控静态资源异常: window.addEventListener('error', function() {}, true) **和4.2有啥区别 window.onerror 可以放两个吗** - 第三个参数为true(捕获状态),能捕获到js执行错误,也能捕获带有src的标签元素的加载错误。 - 第三个参数为false(冒泡状态), 能捕获到js执行错误,不能捕获带有src的标签元素的加载错误。 ```javascript <body> <img src="./aaa.png" /> </body> <script> window.addEventListener('error', (error) => { console.log('捕获静态请求异常:', error); }, true) </script> ``` ![](//img1.jcloudcs.com/developer.jdcloud.com/630447d8-9f0e-4635-9bd2-cb3908774b3820211213144840.png) #### 4.4 unhandledrejection事件监听 - 当Promise被reject且没有reject处理器的时候,会触发unhandledrejection事件 ```javascript new Promise((resolve, reject) => { throw Error('请求出错啦') }) window.addEventListener('unhandledrejection', (error) => { console.log('捕获错误', error) return true }) ``` ![](//img1.jcloudcs.com/developer.jdcloud.com/d6c5cc76-6673-434a-9ea1-d70b90702f3420211213144909.png) #### 4.5 vue.errorHanlder ![](//img1.jcloudcs.com/developer.jdcloud.com/62b8506e-ddb9-4c66-9a9e-b503ba0ea4c120211213144924.jpg) - throw new Error : 代码块中一旦抛出错误就会退出执行 - console.error : 浏览器控制台打印异常信息,不会导致代码退出执行 ### 5 总结 1. 错误异常监控系统可接入系统: http://sgm-web.jd.com 1. 线上错误分析可采用sourseMap分析,具体操作可百度 ------------ ###### 自猿其说Tech-京东物流技术发展部 ###### 作者:张艳娟
原创文章,需联系作者,授权转载
上一篇:敏捷在业务效能中的赋能
下一篇:短链业务全流程笔记
相关文章
前端十年回顾 | 漫画前端的前世今生
Taro小程序跨端开发入门实战
【技术干货】企业级扫描平台EOS关于JS扫描落地与实践!
自猿其说Tech
文章数
426
阅读量
2149964
作者其他文章
01
深入JDK中的Optional
本文将从Optional所解决的问题开始,逐层解剖,由浅入深,文中会出现Optioanl方法之间的对比,实践,误用情况分析,优缺点等。与大家一起,对这项Java8中的新特性,进行理解和深入。
01
Taro小程序跨端开发入门实战
为了让小程序开发更简单,更高效,我们采用 Taro 作为首选框架,我们将使用 Taro 的实践经验整理了出来,主要内容围绕着什么是 Taro,为什么用 Taro,以及 Taro 如何使用(正确使用的姿势),还有 Taro 背后的一些设计思想来进行展开,让大家能够对 Taro 有个完整的认识。
01
Flutter For Web实践
Flutter For Web 已经发布一年多时间,它的发布意味着我们可以真正地使用一套代码、一套资源部署整个大前端系统(包括:iOS、Android、Web)。渠道研发组经过一段时间的探索,使用Flutter For Web技术开发了移动端可视化编程平台—Flutter乐高,在这里希望和大家分享下使用Flutter For Web实践过程和踩坑实践
01
配运基础数据缓存瘦身实践
在基础数据的常规能力当中,数据的存取是最基础也是最重要的能力,为了整体提高数据的读取能力,缓存技术在基础数据的场景中得到了广泛的使用,下面会重点展示一下配运组近期针对数据缓存做的瘦身实践。
自猿其说Tech
文章数
426
阅读量
2149964
作者其他文章
01
深入JDK中的Optional
01
Taro小程序跨端开发入门实战
01
Flutter For Web实践
01
配运基础数据缓存瘦身实践
添加企业微信
获取1V1专业服务
扫码关注
京东云开发者公众号