一套完美的前端体系应少不了异常统计与监控,纵然有充足的质量保证体系,不免会涌现一些意料之外的事,尤其是在庞杂的网路环境和运转环境之下。为了保证代码的硬朗性以及页面的稳定性,我们从多个方面来做异常的提防和监控。
三种思绪
主动防备
关于我们操纵的数据,尤其是由 API 接口返回的,经常会有一个很庞杂的深层嵌套的数据结构。为了代码的硬朗性,许多时刻须要对每一层接见都作空值推断,就像如许:
props.user &&
props.user.posts &&
props.user.posts[0] &&
props.user.posts[0].comments &&
props.user.posts[0].comments[0]
相似的代码人人能够都写过,没写过也许也见到他人写过。看起来确切相本地不美观,有句话说得很棒:
The opposite of beautiful is not ugly, but wrong.
我们得找到一种,更简朴、更文雅、更平安的体式格局来处置惩罚这类情况。参考这篇文章:Safely Accessing Deeply Nested Values In JavaScript,文章提到借助 Ramda、Lenses、Lodash 以及 Immutable.js 等类库的体式格局,并供应一个异常简洁明了的原生解决计划:
function getIn(p, o) {
return p.reduce(function(xs, x) {
return (xs && xs[x]) ? xs[x] : null;
}, o);
}
接下来我们如许接见就能够了:
getIn(['user', 'posts', 0, 'comments'], props)
假如一般接见到,则返回对应的值,不然返回 null
。
这里供应的只是主动防备的一种情况,关于怎样编写更平安的代码这里不作深切睁开。
全局监控
浏览器供应 window.onerror
API 来协助我们举行全局的毛病监控:
- 当 JavaScript 运转时毛病(包括语法毛病)发作时,会实行
window.onerror()
` - 当一项资本(如
<img>
或<script>
)加载失利,能被单一的window.addEventListener
捕获
/**
* @param {String} message 毛病信息
* @param {String} source 发作毛病的剧本URL
* @param {Number} lineno 发作毛病的行号
* @param {Number} colno 发作毛病的列号
* @param {Object} error Error对象
*/
window.onerror = function(message, source, lineno, colno, error) {
// ...
}
个中 error 对象包括细致的毛病客栈信息,在 IE9 之前,没有这个参数。
针对性捕获 try..catch
能够经由过程 try..catch 来主动抓取毛病,想要对一段代码 try..catch,我们能够如许:
try {
// ...
} catch (error) {
handler(error)
}
对一个函数做 try..catch 封装:
function tryify(func) {
return function() {
try {
return func.apply(this, arguments)
} catch (error) {
handleError(error)
throw error
}
}
}
为何是 script error
计划已明白,但另有一些问题。在检察 JavaScript 毛病统计时,发明 80% 以上都是 “script error”。本来,当加载自差别域的剧本中发作语法毛病时,为防止信息泄漏,语法毛病的细节将不会报告,而代之简朴的 “Script error.”
而在大多数情况下,我们的静态资本放在特地的 CDN 服务器上,跟站点并不在一个域,所以假如只是简朴的抓取,只会获得一堆意义不大的 script error
解决计划:
- 增添 CORS 支撑
- 运用 try..catch
增添 CORS 支撑
须要做两点:
1.在 script 便签增添 crossorigin,默认值 crossorigin="anonymous"
<script src="//xxx.com/example.js" crossorigin></script>
在 require.js 里供应一个 onNodeCreated hook,供我们供应扩大,要增添 crossorigin 属性,以下所示:
<script>
// 假如在 require.js 加载之前定义了 requirejs,require.js 会将其作为一个对象传入 requirejs.config
var requirejs = {
onNodeCreated: function(node, config, id, url) {
node.setAttribute('crossorigin', 'anonymous')
}
}
</script>
<script src="//xxx.com/require.js" charset="utf-8"></script>
在 2.2.0 版本以上可用(很遗憾的是,现在的集成解决计划版本恰好低于这个版本)。
2.同时在 CDN 服务器增添相应头 access-control-allow-orgin
,设置许可接见 CORS 的域,不然浏览器直接将制止加载。
try..catch
这一点上面也有提到,算是一种比较通用,可定制强的计划。固然,在机能上也会有一些消耗。
综合斟酌,try..catch 通用性更好,但由于其在机能方面的一些消耗,CORS 优于 try..catch
一个监控小东西
随后,引见一个 JavaScript stack trace 的小东西:https://github.com/CurtisCBS/… ,东西由 Curtis 和 mirreal 共同完成。
主如果用于捕获页面 JavaScript 异常报错,捕获异常范例包括:
- JavaScript runtime 异常捕获 √
- 静态资本 load faided 异常捕获 √
- console.error 的异常捕获 √
- try..catch 毛病捕获 √
运用体式格局也很简朴,但运用 script mode 引入文件后,挪用 init 函数,举行初始化设置和监听
<script src="//unpkg.com/jstracker@latest/dist/jstracker.js"></script>
<script>
jstracker.init({
delay: 1000,
maxError: 10,
sampling: 1,
report: function(errorLogs) {
console.table(errorLogs)
}
})
</script>
假如是运用 module mode,以下:
// npm install jstracker --save
import jstracker from 'jstracker'
jstracker.init({
concat: false,
report: function(errorLogs) {
// console.log('send')
}
})
假如要运用 try..catch 捕获,jstracker 暴露出一个 tryJS
对象,能够处置惩罚 try..catch 包装,就像如许:
import jstracker from 'jstracker';
this.handleSelect = jstracker.tryJS.wrap(this.handleSelect);
一切毛病信息一致由 report 函数处置惩罚,能够在此之上做数据处置惩罚:
// ubt.js
import jstracker from 'jstracker';
import utility from 'utility';
jstracker.init({
concat: false,
report: function(errorLogs) {
const errorLog = errorLogs[0];
errorLog.ua = window.navigator.userAgent;
ubtTracker.send(errorLog);
}
});
const ubtTracker = {
key: {
UBT_JS_TRACKER: 'xxxx-xxxx-xxxx'
},
send(data) {
const value = utility.deserializeUrl(data);
xxxx.send(['trace', this.key.UBT_JS_TRACKER, value]);
}
};
function wrapContext(ctx) {
for (const func in ctx) {
ctx[func] = jstracker.tryJS.wrap(ctx[func]);
}
}
export {
wrapContext,
ubtTracker,
jstracker
};
概述
作为开发者以及项目维护者的身份,我们应该编写更平安硬朗的代码。但由于环境的多样性,不管再完美的测试,code review 都不免都所疏漏,我们须要一套监控体系来完美全部前端体系。
在监控的时刻,出于同源平安策略没法拿到正确的毛病信息,在此,有两种解决计划:
- 增添 CORS 支撑
- 运用 try..catch 举行异常捕获
末了,我们对全部监控事情封装了一个基本的中心,能够监控 JavaScript Runtime 异常,资本加载异常,以及 try..catch 捕获异常等,并给出一个现实事情中的示例。