原文:如何优雅处理前端异常?
异常的种类
- JS 语法错误、代码异常
- Ajax 请求异常
- 静态资源加载异常
- Promise 异常
- iframe 异常
- 跨域 Script error
- 崩溃和卡顿
对于第二点:Ajax 异常,我更偏好称之为 http 异常;对于第四点:Promise 异常,我更偏好称之为异步异常。
异常的处理
针对以上异常的种类,我们来看一下怎么处理:
try-catch 的误区
try-catch 只能捕获到同步的运行时错误,对语法和异步错误却无能为力
window.onerror 并不是万能的
- 同步异常可捕获
- 语法错误不能捕获
- 异步异常可捕获
onerror 最好写在所有 JS 脚本的前面,否则有可能捕获不到错误;onerror 无法捕获语法错误;
window.addEventListener
当静态资源加载失败会触发 error 事件。由于网络请求异常不会事件冒泡,因此必须在捕获阶段将其捕捉到才行,这种方式虽然可以捕捉到网络请求的异常,但是无法判断 HTTP 的状态是 404 还是其他比如 500 等等,所以还需要配合服务端日志才进行排查分析才可以。
Promise Catch
promise 的 catch 可以非常容易地捕获异步的错误。
没有 catch 的 Promise 中抛出的错误无法被 onError 或 try-catch 捕获到。所以务必要写 catch 处理抛出异常。
解决方案: 为了防止有漏掉的 Promise 异常,建议在全局增加一个对 unhandledrejection 的监听,用来全局监听 Uncaught Promise Error。
使用方式:
window.addEventListener("unhandledrejection", function(e) { |
那如果对 Promise 不进行 catch 呢:
window.addEventListener("unhandledrejection", function(e){ |
如果去掉控制台的异常显示,需要加上:
event.preventDefault() |
React 的异常处理
UI 的某部分引起的 JS 错误不应该破坏整个程序,为了帮 React的使用者解决这个问题,React 16介绍了一种关于错误边界
注意: error boundaries并不会捕捉这些错误:
事件处理器
异步代码
服务端的渲染代码
在 error boundaries 区域内的错误
iframe 异常
借助 window.onerror
script 异常
崩溃和卡顿
- 利用 window 对象的 「load」 和 「beforeunload」 事件实现了「网页崩溃」的监控
- 使用 Service Worker 来实现网页崩溃的监控:
- Service Worker 有自己独立的工作线程,与网页区分开,网页崩溃了,Service Worker 下不会崩溃;
- Service Worker 生命周期一般要比网页还要长,可以用来监控网页的状态;
- 网页可以通过 navigator.serviceWorker.controller.postMessage API 向掌管自己的 SW 发送消息
错误上报
- 利用 Ajax 请求上报
- 动态创建 img 标签的形式
上报时,设置采集率以减少服务器压力
Reporter.send = function(data) { |