本次写做来源于一次面试,前端架构师岗位,最后面试官临时给我掏出了一道比较少见的面试题 ,终究斩获offer ,虽然这道题并不难,可是考察的东西挺有趣,加上近期有看到前端防护性编程、优雅处理前端错误的文章,因而想起来把这道题写了下来。html
这是一个关于前端错误处理的题目,由浅入深前端
本题答案: xxxx未定义,致命错误,以前无错误捕获处理机制,页面没有跳转到百度react
第二个版本:webpack
这里仍是比较简单,由于try里面才会捕获错误,一旦抛出错误就会被全局捕获错误的函数捕获 最终输出顺序: try 抛出错误 全局捕获到错误git
加入函数调用版本,问最终打印台输出什么 github
调用test,执行test,执行完了try同步代码后,执行抛出Error,结束test的函数的调用(只要函数内部抛出错误,就会结束这个函数的调用而且出栈),全局捕获到的错误,仍是‘抛出错误’这个咱们本身定义的错误内容,console.log(a)并无被执行到 web
变异版本 面试
这里主要考察的是函数的抛出错误配合finally的执行,咱们一直认为,只要函数内部抛出错误,就会结束这个函数调用,立马出栈。因此return和throw new Error不能在一块儿用,可是finally却仍是依然会执行。finally,顾名思义,最后都会执行ajax
> finally 语句在 try 和 catch 以后不管有无异常都会执行。数据库
加入webpack工程化构建的变异版本,选中此html为模板,问, 若是其余经过webpack构建的文件发生了致命错误,例如由于作了tree sharking,没有兼容低版本浏览器,此时能够捕获到全局错误吗
答案是不能够捕获到,由于通过webpack打包后,代码会变成
若是此时其余模块发生了致命错误,例如const这种代码跑在IE6中,那么就会直接致命错误,阻断浏览器解析代码,页面挂掉。js引擎也不会去解析下面的代码~ 尚未运行到window.onerror这里就挂了
上面只是一个比较简单的面试题,考察错误处理能力,后面是结合React的错误边界,资源请求错误,ajax请求错误等的处理来口述,这里可能须要你平时对这些东西有比较多了解和实践才能hold住
window.onerror与window.addEventListener('error')捕获js运行时错误
使用window.onerror和window.addEventListener('error')都能捕获,可是window.onerror含有详细的error堆栈信息,存在error.stack中,因此咱们选择使用onerror的方式对js运行时错误进行捕获。
资源加载错误使用addEventListener去监听error事件捕获
实现原理:当一项资源(如<img>或<script>)加载失败,加载资源的元素会触发一个Event接口的error事件,并执行该元素上的onerror()处理函数。
这些error事件不会向上冒泡到window,不过能被window.addEventListener在捕获阶段捕获。
但这里须要注意,因为上面提到了addEventListener也可以捕获js错误,所以须要过滤避免重复捕获,判断为资源错误的时候才进行处理。
伪代码
window.addEventListener('error', (e) => {
这样就能够捕获到任意的图片等资源加载错误的信息,可是捕获后依旧会有爆红提示,我猜测这种资源请求错误是很是重要的,必须爆出来?
Error Boundaries(错误边界)配合webpack+系统的onerror错误捕获
有人说使用 create-react-app 建立的项目,在开发环境,就算使用了 componentDidCatch 或者 getDerivedStateFromError,错误依然会被抛出,在 build 后,错误将会捕获,不会致使整个项目卸载(这点我不肯定,由于我都是本身配脚手架的)
根据官方文档所说,在 react 16 之后,任何未被错误边界捕获的错误将会致使整个 React 组件树被卸载。因此咱们在开发项目时,须要去捕获错误边界的错误,并提供一个备用UI,那么被错误边界捕获的错误,还会冒泡到window中吗
多说无益,咱们先实践
咱们先定义一个错误边界,而后html模板文件中,依旧有咱们的那段代码
此时将错误边界组件包裹APP根组件~
运行代码,一切正常
此时React根组件的componentDidmount生命周期函数抛出错误
抛出错误后,被错误边界捕获
说明这种错误被React错误边界捕获后,就不会再被onerror函数捕获,那么window.addEventListenr呢? 尝试一下。
一样,也没有被捕获,通过测试,dom2形式监听error事件,不管第三个参数是false仍是true,只要被错误边界捕获后,都不会再被捕获。
接下来是语法错误
若是是同步的语法错误,在try catch中就能够被捕获,不会冒泡到window.onerror事件中
异步语法错误
最终被全局到error回调函数捕获,可是你们很奇怪,这里为何捕获了,还会爆出错误?咱们以前是不会的。
这里要说明一点,若是是人为抛出错误 throw new Error,error函数是能够捕获的。可是一旦是语法错误,那么须要在error函数中return true,这样异常才不会往上继续抛出。
当咱们打开return true 时候
全局错误捕获,而且控制台不会出现未捕获的错误了~
细心的朋友会发现,控制台一直有一个报错,没错,这是一个静态资源的请求,img标签。
项目中有一段这个代码
<img src="ssss" alt=""/>
最终返回响应是:
**这里能够肯定,静态资源请求错误,不会冒泡到window.error事件中,只能够经过上面的dom2形式经过在捕获阶段捕获到这个错误
**
window.addEventListener('error', (e) => {
dom2形式捕获到了这个请求资源错误,并且同时触发了这个标签的onerror事件
<img src="ssss" alt="" onError={(e)=>{console.log('图片加载失败',e)}}/>
一些图片的处理,能够相似这样,当请求的静态资源出现错误时候,能够更换请求地址
,不会致使碎图
Promise的捕获,对于频繁调用的函数,确定是须要封装成promise风格的,统一处理错误,统一接口捕获一次就能够了,由于onerror函数并不能捕获promise错误,这里我就不演示了
> 网络请求错误也是不会被error函数捕获的,可是咱们能够封装成promise风格,统一本身catch错误处理
因为async await函数和promise可能比较多,项目中,为了防止没有捕获的promise出现,咱们可使用
这样就能够经过unhandledrejection这个事件捕获到没有处理错误的promise
对于错误上报,通常是采用不会跨域的请求,例如img标签、audio标签等静态资源get请求后面将error信息拼接,后台截取查询字符串存入数据库和缓存中提供记录和查询能力
new Image().src = `${url}?err=${error}`;
这样后端就能够接受到异常错误信息了
好久以前看过有用Performance和beforeunload, servece worker去处理极端状况的,你们有兴趣也能够去看看,我这里就不作过多的介绍,前者使用也比较简单,后者并不太适用每一个人。
因为如今的错误监控、上报已经造成了一套完整的商业链,这方面并非个人强项,若是写得不对的地方,欢迎指出,架构师岗位面试,更考察你对项目总体把控能力,最后出现这个题目,我以为也正常
本开源项目gitHub地址(React和webpack,练手适合):
https://github.com/JinJieTan/react-webpack
若是感受写得不错,能够帮忙点个-在看
但愿每一个人都会像老许同样
有人问你,你要老婆/老公不要?
要的话,就给你送来