【澳门葡京】前者品质与特别申报,前端监察和控制和前端埋点方案设计

前者监察和控制和前端埋点方案设计

2018/08/29 · JavaScript
· 埋点

原稿出处: yuxiaoliang   

在线上体系中,须求计算产品中用户作为和应用意况,从而得以从用户和成品的角度去询问用户群众体育,从而升级和迭代产品,使其更为靠近用户。用户作为数据能够经过前端数据监察和控制的艺术获得,除此之外,前端还亟需完结品质监察和控制和丰裕监察和控制。质量监察和控制包含首屏加载时间、白屏时间、http请求时间和http响应时间。非常监察和控制包蕴前端脚本执行报错等。

完结前端监察和控制有四个步骤:前端埋点和反映、数据处理和数码解析。本文针对全部前端监察和控制,设计适用的方案。本文的要害内容分为:

  • 怎么必要前端监察和控制
  • 常用前端埋点方案总括
  • 前端埋点方案选型和前端上报方案设计
  • 前端监察和控制结果可视化展示系统的规划

原稿的地址,在自家的博客中:https://github.com/forthealll…

如有帮助,您的star是对自个儿最好的鼓励~

1. 产业界案例

近日前端质量监控系统大约为分两类:以GA为代表的代码监察和控制和以webpagetest为代表的工具监察和控制

代码监察和控制寄予于js代码并配置到需监督检查的页面,手动计算时间差或然选拔浏览器的的API进行数据总结。

影响代码监察和控制数据的成分有以下三种:

  • 浏览器渲染机制;
  • 浏览器对API的落到实处程度,比如performance API;

工具监控永不将总计代码陈设到页面中,一般依托于虚拟机。以webpageTest为例,输入需总结的url并且选取运维次url的浏览器版本,webpageTest后台虚拟机对url进行呼吁分析后便足以付出各样品质目的,比如瀑布流、静态文件数量、首屏渲染时间等等。

代码监察和控制和工具监察和控制的比较如下表:
澳门葡京 1

依据如今事务必要以及资产预算,最终决定动用代码监察和控制方案。以下分别介绍代码监察和控制各地方的达成细节。

前者品质与那几个申报

2018/08/22 · 基本功技术 ·
性能

最初的小说出处: counterxing   

由于工作计划原因,有幸2回接触产品运转的埋点义务。1回埋点发现自家对埋点机理未根本弄清、明晰,由此整理了一些工作中的笔记及相关资料。如有错误之处,望请不吝赐教。

一 、为啥须求前端监察和控制

前者监察和控制的目标是:

获得用户作为以及跟踪产品在用户端的应用意况,并以监察和控制数据为根基,指明产品优化的方向

前者监察和控制可以分为三类:数据监察和控制、品质监察和控制和丰裕监察和控制。上面大家来挨家挨户的询问。

2. 前端质量监察和控制指标

前者品质总括的数据大概有以下多少个:

  • 白屏时间:从打开网站到有内容渲染出来的光阴节点;
  • 首屏时间:首屏内容渲染完结的小运节点;
  • 用户可操作时间节点:domready触发节点;
  • 总下载时间:window.onload的触发节点。

上边介绍三种以上多少个数据的计算方案。

概述

对于后台开发以来,记录日志是一种格外普遍的付出习惯,常常大家会采取try...catch代码块来积极抓获错误、对于每回接口调用,也会记录下每一回接口调用的时日花费,以便大家监察和控制服务器接口品质,进行问题排查。

刚进公司时,在进展Node.js的接口开发时,作者不太习惯每一回排查难题都要由此跳板机登上服务器看日志,后来稳步习惯了那种办法。

举个例子:

JavaScript

/** * 获取列表数据 * @parma req, res */ exports.getList = async
function (req, res) { //获取请求参数 const openId =
req.session.userinfo.openId; logger.info(`handler getList, user openId
is ${openId}`); try { // 得到列表数据 const startTime = new
Date().getTime(); let res = await ListService.getListFromDB(openId);
logger.info(`handler getList, ListService.getListFromDB cost time ${new
Date().getTime() – startDate}`); // 对数码处理,再次来到给前端 // … }
catch(error) { logger.error(`handler getList is error,
${JSON.stringify(error)}`); } };

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 获取列表数据
* @parma req, res
*/
exports.getList = async function (req, res) {
    //获取请求参数
    const openId = req.session.userinfo.openId;
    logger.info(`handler getList, user openId is ${openId}`);
 
    try {
        // 拿到列表数据
        const startTime = new Date().getTime();
        let res = await ListService.getListFromDB(openId);
        logger.info(`handler getList, ListService.getListFromDB cost time ${new Date().getTime() – startDate}`);
        // 对数据处理,返回给前端
        // …
    } catch(error) {
        logger.error(`handler getList is error, ${JSON.stringify(error)}`);
    }
};

以下代码经常会油然则生在用Node.js的接口中,在接口中会总括查询DB所耗费时间间、亦大概计算RPC劳动调用所耗费时间间,以便监测质量瓶颈,对质量做优化;又或许对尤其使用try ... catch当仁不让抓获,以便随时对标题展开回想、还原难题的场景,举办bug的修复。

而对在此以前端来说吧?能够看之下的气象。

方今在拓展三个供给开发时,偶尔发现webgl渲染印象失败的状态,大概说印象会油可是生解析战败的情状,大家只怕根本不知道哪张印象会解析或渲染失败;又或如眼前支出的其它多少个要求,大家会做一个有关webgl渲染时间的优化和形象预加载的急需,假如缺点和失误品质监察和控制,该如何总计所做的渲染优化和形象预加载优化的优化比例,怎么着验证自个儿所做的工作具有价值吧?只怕是透过测试同学的黑盒测试,对优化前后的时间展开录屏,分析从进入页面到影象渲染完毕到底经过了略微帧图像。那样的多少,恐怕既不纯粹、又比较片面,设想测试同学并不是当真的用户,也不只怕苏醒真实的用户他们所处的互联网环境。回过头来发现,大家的项目,尽管在服务端层面做好了日志和品质总计,但在前者对这一个的督察和总体性的总计。对于前端的性质与那多少个申报的势头探索是有必不可少的。

正文将第壹商量对数量的埋点方式和反馈收集,而非对数码的辨析。前者对到现在天使用的方法有相比统一的认识,后者数据解析在不一样行业、公司有一定独立的规则,又由于店铺保密性原因,在此不撰写了。

(1)数据监察和控制

数码监察和控制,顾名思义便是监听用户的行为。常见的多寡监察和控制包含:

  • PV/UV:PV(page
    view),即页面浏览量或点击量。UV:指访问有些站点或点击某条情报的不比IP地址的食指
  • 用户在每八个页面包车型大巴停留时间
  • 用户通过如何入口来访问该网页
  • 用户在相应的页面中触发的作为

总结那么些多少是有含义的,比如我们领悟了用户来源的沟渠,能够带动产品的放大,知道用户在每四个页面停留的年华,能够针对停留较长的页面,扩充广告推送等等。

2.1 常规总计方案

运用注入代码监察和控制的点子总括以上指标,在平素不一些浏览器新API(如下文将波及的timing
API)的帮助下,获得的数据大约是估值,即便不准确,但也有肯定的参考价值。

格外捕获

对于前端来说,大家必要的不胜捕获无非为以下三种:

  • 接口调用情状;
  • 页面逻辑是或不是错误,例如,用户进入页面后页面彰显白屏;

对此接口调用意况,在前者日常需求申报客户端相关参数,例如:用户OS与浏览器版本、请求参数(如页面ID);而对于页面逻辑是否错误难点,平常除了用户OS与浏览器版本外,需求的是报错的堆栈消息及实际报错地方。

① 、埋点是如何

定时、定点地在对象应用/网站上征集数据,将数据以日记的方法申报至服务器的进程。

(2)品质监察和控制

品质监察和控制指的是监听前端的性质,主要包括监听网页大概说产品在用户端的体验。常见的性格监察和控制数据包涵:

  • 不等用户,区别机型和分歧系统下的首屏加载时间
  • 【澳门葡京】前者品质与特别申报,前端监察和控制和前端埋点方案设计。白屏时间
  • http等请求的响应时间
  • 静态能源总体下载时间
  • 页面渲染时间
  • 页面交互动画完成时间

那个质量监察和控制的结果,能够来得前端质量的好坏,依据品质监测的结果能够进一步的去优化前端品质,比如协作低版本浏览器的卡通效果,加速首屏加载等等。

2.1.1 白屏时间

白屏时间节点指的是从用户进入网站(输入url、刷新、跳转等艺术)的随时开头估量,一向到页面有内容呈现出来的日子节点。这么些进度包蕴dns查询、建立tcp连接、发送第一个http请求(固然选用https还要参加TLS的证实时间)、重返html文档、html文书档案head解析达成。

选拔注入代码监察和控制不恐怕获取解析html文书档案此前的时刻新闻,近来周边应用的白屏时间总结方案是在html文书档案的head中享有的静态财富以及内嵌脚本/样式从前记录叁个时间点,在head最底部记录另贰个时间点,两者的差值作为白屏时间。如下:

<html>
<head>
<meta charset="UTF-8"/>
<!--这里还有一大串meta信息-->
<script>
var start_time = new Date();//统计起点,实际为html开始解析的时间节点
</script>
<link href='a.css'></link>
<script src='a.js'></script>
<script>
var end_time = new Date();//统计起点,实际为html开始解析的时间节点
</script>
</head>
<body>
</body>
</html>

上述代码中的end_timestart_time的差值一般作为白屏时间的估值,但辩驳上来讲,那几个差值只是浏览器解析html文书档案head的时刻,并非规范的白屏时间。

不行捕获方法

② 、为啥要埋点

商行方得到用户在产品上的采纳数据,分析后便于产品优化迭代。

(3)格外监察和控制

别的,产品的前端代码在履行进程中也会发生尤其,因而须求引入分外监察和控制。及时的上报格外情状,能够幸免线上故障的发上。固然超过61%百般能够经过try
catch的艺术削株掘根,可是比如内部存款和储蓄器泄漏以及其余偶现的不胜麻烦捕获。常见的急需监察和控制的百般包罗:

  • Javascript的那么些监察和控制
  • 体制丢失的要命监察和控制
2.1.2 首屏时间

首屏时间的总计相比较复杂,方今使用比较广的方案是将首屏的图片、iframe等能源添加onload事件,获取最慢的叁个。

那种方案相比较符合首屏成分数量稳定的页面,比如移动端首屏不论显示屏尺寸都来得相同数量的始末,响应式得改变内容的字体、尺寸等。但是对于首屏成分不稳定的页面,那种方案并不适用,最特异的正是PC端页面,不一致显示屏尺寸下显得的首屏内容见仁见智。上述方案便不适用于此场景。

大局捕获

能够因而全局监听非凡来捕获,通过window.onerror或者addEventListener,看以下例子:

JavaScript

window.onerror = function(errorMessage, scriptU帕杰罗I, lineNo, columnNo,
error) { console.log(‘errorMessage: ‘ + errorMessage); // 相当音讯console.log(‘scriptU奥迪Q3I: ‘ + scriptU奥迪Q5I); // 格外文件路径
console.log(‘lineNo: ‘ + lineNo); // 万分行号 console.log(‘columnNo: ‘ +
columnNo); // 非常列号 console.log(‘error: ‘ + error); // 很是堆栈音讯// … // 卓殊上报 }; throw new Error(‘那是3个错误’);

1
2
3
4
5
6
7
8
9
10
window.onerror = function(errorMessage, scriptURI, lineNo, columnNo, error) {
  console.log(‘errorMessage: ‘ + errorMessage); // 异常信息
  console.log(‘scriptURI: ‘ + scriptURI); // 异常文件路径
  console.log(‘lineNo: ‘ + lineNo); // 异常行号
  console.log(‘columnNo: ‘ + columnNo); // 异常列号
  console.log(‘error: ‘ + error); // 异常堆栈信息
  // …
  // 异常上报
};
throw new Error(‘这是一个错误’);

澳门葡京 2

通过window.onerror事件,能够赢得切实的那贰个音讯、很是文件的U中华VL、很是的行号与列号及特别的仓库音讯,再捕获至极后,统一举报至大家的日记服务器。

亦或是,通过window.addEventListener艺术来进展特别申报,道理同理:

JavaScript

window.add伊芙ntListener(‘error’, function() { console.log(error); // …
// 卓殊上报 }); throw new Error(‘那是一个谬误’);

1
2
3
4
5
6
window.addEventListener(‘error’, function() {
  console.log(error);
  // …
  // 异常上报
});
throw new Error(‘这是一个错误’);

澳门葡京 3

③ 、埋点有哪些措施

② 、常用前端埋点方案总计

在上一节中介绍了前者监察和控制的成效,那么怎么样兑现前端监察和控制呢,达成前端监察和控制的步子为:前端埋点和申报、数据处理和多少解析。首要的步骤便是前者埋点和反映,也正是数据的采访阶段。数据搜集的丰盛性和准确性会影响对产品线上作用的辨识结果。

当上周边的前端埋点方法分为两种:代码埋点、可视化埋点和无痕埋点。上面一一介绍每种埋点的方法。

2.1.3 可操作时间

用户可操作的光阴节点即dom
ready触发的时光,使用jquery能够透过$(document).ready()获得此数据,假使不采取jQuery能够参见这里由此原生方法落成dom
ready。

try… catch

使用try... catch虽说能够较好地展开充足捕获,不至于使得页面由于一处错误挂掉,但try ... catch抓获格局体现过分臃肿,大多代码应用try ... catch打包,影响代码可读性。

(1) 代码埋点

原理:在应用App或界面起头化时,初始化埋点的SDK,在触发某些节点(如事件/页面)时调用SDK相应的法门,通过接口发送数据。日常为了削减用户反馈数据时消耗过多流量,常见有三种缓解方案:

(一)
举办数据映射(简化数据,不传具体参数值,而是依照MAP-KEY映射关系),如应用端发送(0/0、1/)数据,由服务端将依照预订文书档案映射为(首页/模块① 、第二个点击事件);

(二)
非即时发送数据,将多条数据压缩打包,等待网络境况特出、或定时(5min)发送至服务端。

优点:

天性化自定义,能够依据公司自笔者工作性情自定义属性、事件,定制化获取数据。

缺点:

(一)
人力开支高,埋点工程涉及到由运行-产品-前端-服务端-后台一文山会海具有数据团队,差异种类/版本不易管理,全部办法均需人工注入,数据收集后需由服务端实行解析;

(二)
版本更新前后,不难生出多少错乱(若发生首要领导离职,无相关文档沉淀,则大概引致“全盘皆输”的事态);

(三)
起步难,早先时代为简单计数;要求商行长期且平静地完善、不断根据业务立异。

(1) 代码埋点

代码埋点,便是以放权代码的花样进行埋点,比如需求监控用户的点击事件,会采纳在用户点击时,插入一段代码,保存这几个监听行为可能间接将监听行为以某一种多少格式直接传送给server端。此外比如须求总计产品的PV和UV的时候,须要在网页的开端化时,发送用户的访问音信等。

代码埋点的长处:

  • 可以在随意时刻,精确的出殡或保存所急需的数目音讯。

缺点:

  • 工作量较大,每二个零件的埋点都急需丰盛相应的代码
2.1.4 总下载时间

总下载时间即window.onload接触的流年节点。

此时此刻多数web产品都有异步加载的剧情,比如图片的lazyload等。如果总下载时间必要总括到这么些数量,能够借鉴AOP的见解,在呼吁异步内容前边和今后分别打点,最终计算差值。可是普通来讲,大家说的总下载时间并不包括异步加载的内容。

科学普及难题

(2) 可视化埋点(又称作框架化埋点)

原理:将着力代码与能源、配置分开,当应用App运转时从服务端更新配备和财富(plist),应用获知后,依照布置和布置新闻相上报数据内容。

完结方式:

(一)
在需埋点的App中放到SDK,开启可视化埋点情势,并联通后台。嵌入的SDK依照后台供给,定时制作截图,制作截图时会将页面上具备指标进行遍历,遍历该页面上独具指标(如按钮、列表、View视图),获取其类名、属性、页面下坐标、长度宽度高等各地点消息;

(二)
应用将上述数据上传至后台,后台依照截屏和数目重复渲染页面,并且将可埋点的对象标识出来;

(三)
埋点使用者在截屏画面上摘取相应需埋点的指标,后台依照埋点实行事件涉及方面包车型客车布署,并将其保存和配置;

(四)
应用中的SDK在起步或例行轮询时下载配置新闻,依据安排音信,对相应对象添加行为监听,依照行为向服务端发送相应数据。

下图截取神策数据的可视化埋点的后台操作截图作为验证。

优点:

缓解了代码埋点人工开支和换代代价大的题材,只要在本子内有相应SDK,即不设有老版本迭代后无埋点难点;且对于不懂代码的成品运行,可透过后台可视化界面举行配置操作,并且生效。

缺点:

(一) 无法完毕自定义获取数据,可视化埋点覆盖的机能有限;

(二)
集团针对SDK开发难度比较代码埋点大,使用第2方SDK财富则有共同通病,下文说明。

(2)可视化埋点

透过可视化交互的手腕,代替代码埋点。将业务代码和埋点代码分离,提供四个可视化交互的页面,输入为工作代码,通过那个可视化系统,能够在作业代码中自定义的加码埋点事件等等,最终输出的代码耦合了作业代码和埋点代码。

可视化埋点听起来相比较高大上,实际上跟代码埋点依旧分别一点都不大。也正是用二个系列来贯彻手动插入代码埋点的经过。

缺点:

  • 可视化埋点能够埋点的控件有限,不可能手动定制。

2.2 使用window.performance API

window.performance
是W3C质量小组引入的新的API,近期IE9以上的浏览器都辅助。多个performance对象的完好结构如下图所示:
澳门葡京 4

memory字段代表JavaScript对内部存款和储蓄器的占有。

navigation字段总结的是部分网页导航相关的数目:

  1. redirectCount:重定向的数额(只读),然则这些接口有同源策略限制,即仅能检查和测试同源的重定向;
  2. type 重回值应该是0,1,2 中的四个。分别对应多个枚举值:
    • 0 : TYPE_NAVIGATE
      (用户通过平常导航航空模型型式访问页面,比如点三个链接,大概一般的get情势)
    • 1 : TYPE_RELOAD
      (用户通过刷新,包蕴JS调用刷新接口等措施访问页面)
    • 2 : TYPE_BACK_FOKugaWA宝马X5D (用户通过后退按钮访问本页面)

最重要的是timing字段的总计数据,它涵盖了互连网、解析等一多重的时日数额。

跨域脚本不大概准确捕获十分

一般意况下,咱们会把静态资源,如JavaScript剧本放到专门的静态财富服务器,亦大概CDN,看以下例子:

<澳门葡京,!DOCTYPE html> <html> <head>
<title></title> </head> <body> <script
type=”text/javascript”> // 在index.html window.onerror =
function(errorMessage, scriptURI, lineNo, columnNo, error) {
console.log(‘errorMessage: ‘ + errorMessage); // 非凡音讯console.log(‘scriptU猎豹CS6I: ‘ + scriptUSportageI); // 万分文件路径
console.log(‘lineNo: ‘ + lineNo); // 十分行号 console.log(‘columnNo: ‘ +
columnNo); // 至极列号 console.log(‘error: ‘ + error); // 非凡堆栈消息// … // 非凡上报 }; </script> <script
src=”./error.js”></script> </body> </html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html>
<head>
  <title></title>
</head>
<body>
  <script type="text/javascript">
    // 在index.html
    window.onerror = function(errorMessage, scriptURI, lineNo, columnNo, error) {
      console.log(‘errorMessage: ‘ + errorMessage); // 异常信息
      console.log(‘scriptURI: ‘ + scriptURI); // 异常文件路径
      console.log(‘lineNo: ‘ + lineNo); // 异常行号
      console.log(‘columnNo: ‘ + columnNo); // 异常列号
      console.log(‘error: ‘ + error); // 异常堆栈信息
      // …
      // 异常上报
    };
 
  </script>
  <script src="./error.js"></script>
</body>
</html>

JavaScript

// error.js throw new Error(‘那是1个谬误’);

1
2
// error.js
throw new Error(‘这是一个错误’);

澳门葡京 5

结果显示,跨域之后window.onerror根本捕获不到科学的不得了新闻,而是统一重回1个Script error

不留余地方案:对script标签扩充四个crossorigin=”anonymous”,并且服务器添加Access-Control-Allow-Origin

<script src=””
crossorigin=”anonymous”></script>

1
<script src="http://cdn.xxx.com/index.js" crossorigin="anonymous"></script>

(3) 无埋点(全埋点)

规律:在App中放到SDK,做联合的“全埋点”,将应用App中尽量多的多寡收集下来,通过界面配置的艺术对第②行为开始展览定义,对定义的数量举行分析。

完成格局:

在利用中置放SDK,通过可视化格局(即上文可视化埋点形式),针对对象开始展览定义,服务端对定义的数目举办分析,后台加以表现。

优点:

提供了埋点的“后悔药”(数据回看难题),只要陈设了SDK,数据便起始征集;能够自行获得很多启发性的新闻,能够通过热力图向用户显示各类控件、事件点击的可能率更大;便于使用者发现页面僵尸按钮等等。

缺点:

(一)
缺点与可视化埋点相同,未缓解个性化自定义获取数据的标题,贫乏数据获得的灵活性;

(二)
集团针对SDK开发难度较大,一般由数据解析公司研究开发提供,使用第2方提供的埋点方案,有如下缺陷:

壹 、数据源丢失,应用上报的数据上传至第一方服务端,大概引致集团泄密或用户的重庆大学数据丢失;

二 、供应商数量丢包难题,不可能依照使用个性开始展览考订。

(3)无埋点

无埋点并不是说不须求埋点,而是一切埋点,前端的随机3个事变都被绑定1个标识,全部的事件都别记录下来。通过为期上传记录文件,同盟文件分析,解析出来我们想要的数据,并生成可视化报告供专业职员分析就此实现“无埋点”总结。

从言语层面完成无埋点也不会细小略,比如从页面包车型地铁js代码中,找出dom上被绑定的事件,然后开始展览全埋点。

无埋点的优点:

  • 由于采集的是全量数据,所以产品迭代进度中是不需求关注埋点逻辑的,也不会油但是生漏埋、误埋等场景

缺点:

  • 无埋点采集全量数据,给多少传输和服务器扩充压力
  • 没辙灵活的定制各样事件所须要上传的数据
2.2.1 timing API

timing的完整布局如下图所示:
澳门葡京 6

各字段的意义如下:

  • startTime:有个别浏览器达成为navigationStart.aspx),代表浏览器开端unload前三个页面文书档案的上羊时间节点。比如大家当前正值浏览baidu.com,在地点栏输入google.com并回车,浏览器的执行动作依次为:unload当前文书档案(即baidu.com)->请求下一文书档案(即google.com)。navigationStart的值正是触发unload当前文书档案的年月节点。

    比方当前文书档案为空,则navigationStart的值等于fetchStart。

  • redirectStartredirectEnd:假若页面是由redirect而来,则redirectStart和redirectEnd分别代表redirect初步和得了的日子节点;

  • unloadEventStartunloadEventEnd:要是前一个文书档案和请求的文书档案是同三个域的,则unloadEventStartunloadEventEnd各自代表浏览器unload前贰个文书档案的开端和甘休时间节点。不然双方都等于0;
  • fetchStart是指在浏览器发起任何请求在此以前的日子值。在fetchStart和domainLookupStart以内,浏览器会检讨当前文书档案的缓存;
  • domainLookupStartdomainLookupEnd各自代表DNS查询的启幕和终结时间节点。要是浏览器没有开始展览DNS查询(比如动用了cache),则两者的值都等于fetchStart
  • connectStartconnectEnd各自代表TCP建立连接和再而三成功的日子节点。假如浏览器没有举办TCP连接(比如动用持久化连接webscoket),则两者都等于domainLookupEnd
  • secureConnectionStart:可选。借使页面使用HTTPS,它的值是平安连接握手在此以前的随时。假设该属性不可用,则再次回到undefined。假设该属性可用,但未曾使用HTTPS,则重回0;
  • requestStart表示浏览器发起呼吁的光阴节点,请求的法门能够是呼吁服务器、缓存、本地财富等;
  • responseStartresponseEnd分级表示浏览器收到从劳动器端(或缓存、本地能源)响应回的首先个字节和最后贰个字节数据的随时;
  • domLoading表示浏览器起初解析html文书档案的日子节点。大家领会IE浏览器下的document有readyState属性,domLoading的值就十二分readyState改变为loading的大运节点;
  • domInteractive表示浏览器解析html文书档案的情事为interactive时的小时节点。domInteractive不要DOMReady,它早于DOMReady触发,代表html文书档案解析完成(即dom
    tree创立完毕)不过内嵌能源(比如外链css、js等)还未加载的时间点;
  • domContentLoadedEventStart:代表DOMContentLoaded事件触发的大运节点:

    页面文书档案完全加载并分析完成之后,会触发DOMContentLoaded事件,HTML文书档案不会等待样式文件,图片文件,子框架页面包车型客车加载(load事件能够用来检查和测试HTML页面是或不是完全加载完毕(fully-loaded))。

  • domContentLoadedEventEnd:代表DOMContentLoaded事件形成的年华节点,此刻用户能够对页面进行操作,也等于jQuery中的domready时间;

  • domComplete:html文书档案完全解析完结的小时节点;
  • loadEventStartloadEventEnd个别表示onload事件触发和完工的时日节点

sourceMap

万般在生养条件下的代码是通过webpack打包后回落混淆的代码,所以大家恐怕会遇上这么的题材,如图所示:

澳门葡京 7

作者们发现具有的报错的代码行数都在率先行了,为啥吧?那是因为在生养环境下,我们的代码被压缩成了一条龙:

JavaScript

!function(e){var n={};function r(o){if(n[o])return n[o].exports;var
t=n[o]={i:o,l:!1,exports:{}};return
e[o].call(t.exports,t,t.exports,r),t.l=!0,t.exports}r.m=e,r.c=n,r.d=function(e,n,o){r.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:o})},r.r=function(e){“undefined”!=typeof
Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:”Module”}),Object.defineProperty(e,”__esModule”,{value:!0})},r.t=function(e,n){if(1&n&&(e=r(e)),8&n)return
e;if(4&n&&”object”==typeof e&&e&&e.__esModule)return e;var
o=Object.create(null);if(r.r(o),Object.defineProperty(o,”default”,{enumerable:!0,value:e}),2&n&&”string”!=typeof
e)for(var t in e)r.d(o,t,function(n){return e[n]}.bind(null,t));return
o},r.n=function(e){var n=e&&e.__esModule?function(){return
e.default}:function(){return e};return
r.d(n,”a”,n),n},r.o=function(e,n){return
Object.prototype.hasOwnProperty.call(e,n)},r.p=””,r(r.s=0)}([function(e,n){throw
window.onerror=function(e,n,r,o,t){console.log(“errorMessage:
“+e),console.log(“scriptURI: “+n),console.log(“lineNo:
“+r),console.log(“columnNo: “+o),console.log(“error: “+t);var
l={errorMessage:e||null,scriptURI:n||null,lineNo:r||null,columnNo:o||null,stack:t&&t.stack?t.stack:null};if(XMLHttpRequest){var
u=new
XMLHttpRequest;u.open(“post”,”/middleware/errorMsg”,!0),u.setRequestHeader(“Content-Type”,”application/json”),u.send(JSON.stringify(l))}},new
Error(“那是3个荒唐”)}]);

1
!function(e){var n={};function r(o){if(n[o])return n[o].exports;var t=n[o]={i:o,l:!1,exports:{}};return e[o].call(t.exports,t,t.exports,r),t.l=!0,t.exports}r.m=e,r.c=n,r.d=function(e,n,o){r.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:o})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,n){if(1&n&&(e=r(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(r.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var t in e)r.d(o,t,function(n){return e[n]}.bind(null,t));return o},r.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(n,"a",n),n},r.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},r.p="",r(r.s=0)}([function(e,n){throw window.onerror=function(e,n,r,o,t){console.log("errorMessage: "+e),console.log("scriptURI: "+n),console.log("lineNo: "+r),console.log("columnNo: "+o),console.log("error: "+t);var l={errorMessage:e||null,scriptURI:n||null,lineNo:r||null,columnNo:o||null,stack:t&&t.stack?t.stack:null};if(XMLHttpRequest){var u=new XMLHttpRequest;u.open("post","/middleware/errorMsg",!0),u.setRequestHeader("Content-Type","application/json"),u.send(JSON.stringify(l))}},new Error("这是一个错误")}]);

在笔者的费用进度中也境遇过那个题材,笔者在支付贰个效能组件库的时候,使用npm link了自作者的零件库,可是出于组件库被npm link后是包裹后的生育环境下的代码,全体的报错都一定到了第贰行。

化解办法是开启webpacksource-map,大家选拔webpack包裹后的浮动的一份.map的台本文件就足以让浏览器对不当地方进行追踪了。此处能够参照webpack
document。

实际上正是webpack.config.js中丰裕一行devtool: 'source-map',如下所示,为示范的webpack.config.js

JavaScript

var path = require(‘path’); module.exports = { devtool: ‘source-map’,
mode: ‘development’, entry: ‘./client/index.js’, output: { filename:
‘bundle.js’, path: path.resolve(__dirname, ‘client’) } }

1
2
3
4
5
6
7
8
9
10
var path = require(‘path’);
module.exports = {
    devtool: ‘source-map’,
    mode: ‘development’,
    entry: ‘./client/index.js’,
    output: {
        filename: ‘bundle.js’,
        path: path.resolve(__dirname, ‘client’)
    }
}

webpack包装后转变对应的source-map,那样浏览器就可见稳定到具体错误的职位:

澳门葡京 8

开启source-map的症结是包容性,近来唯有Chrome浏览器和Firefox浏览器才对source-map支撑。但是我们对这一类情形也有消除办法。能够运用引入npm库来援救source-map,能够参照mozilla/source-map。这个npm库既可以运作在客户端也得以运维在服务端,但是更为推荐的是在服务端使用Node.js对接受到的日记音信时利用source-map解析,以幸免源代码的透漏导致风险,如下代码所示:

JavaScript

const express = require(‘express’); const fs = require(‘fs’); const
router = express.Router(); const sourceMap = require(‘source-map’);
const path = require(‘path’); const resolve = file =>
path.resolve(__dirname, file); // 定义post接口 router.get(‘/error/’,
async function(req, res) { // 获取前端传过来的报错对象 let error =
JSON.parse(req.query.error); let url = error.scriptUQashqaiI; // 压缩文件路径
if (url) { let fileUrl = url.slice(url.indexOf(‘client/’)) + ‘.map’; //
map文件路径 // 解析sourceMap let consumer = await new
sourceMap.SourceMapConsumer(fs.readFileSync(resolve(‘../’ + fileUrl),
‘utf8’)); // 重回1个promise对象 // 解析原始报错数据 let result =
consumer.originalPositionFor({ line: error.lineNo, // 压缩后的行号
column: error.columnNo // 压缩后的列号 }); console.log(result); } });
module.exports = router;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const express = require(‘express’);
const fs = require(‘fs’);
const router = express.Router();
const sourceMap = require(‘source-map’);
const path = require(‘path’);
const resolve = file => path.resolve(__dirname, file);
// 定义post接口
router.get(‘/error/’, async function(req, res) {
    // 获取前端传过来的报错对象
    let error = JSON.parse(req.query.error);
    let url = error.scriptURI; // 压缩文件路径
    if (url) {
        let fileUrl = url.slice(url.indexOf(‘client/’)) + ‘.map’; // map文件路径
        // 解析sourceMap
        let consumer = await new sourceMap.SourceMapConsumer(fs.readFileSync(resolve(‘../’ + fileUrl), ‘utf8’)); // 返回一个promise对象
        // 解析原始报错数据
        let result = consumer.originalPositionFor({
            line: error.lineNo, // 压缩后的行号
            column: error.columnNo // 压缩后的列号
        });
        console.log(result);
    }
});
module.exports = router;

如下图所示,我们已经能够看来,在服务端已经打响解析出了实际错误的行号、列号,大家能够透过日记的点子举行记录,达到了前者至极监察和控制的指标。

澳门葡京 9

④ 、埋点上报的通用数据消息

指的是通用数据新闻,只假若事关到代码埋点,一般都会拿走如下数据。一般是在使用运营时,将相关数据开始展览申报。(也有举不胜举施用如QQ空间,全部的日志上报参数仍包罗通用数据信息)

(一)
无限局域网地址(MAC地址):定义网卡地址,又叫做物理地址、硬件地址,具有全球唯一性,用于定义互联网设施的地点。

(二)
手机设备号(IMEI):移动设备国际识别码,是手提式有线话机的绝无仅有标识码。用于区分终端唯一性,对于用户去重有肯定意义;与MAC地址协同应用。

(三)
终端系统/系统版本号:获取极限系统以及版本号,在查询某个版本上冒出特定bug,具有一定协理意义;(别的用途待发现补充)

(四) 应用版本号:有利于版本迭代控制,作为数据的标志;

(五)
网络状态:获取当前网络为3G/4G/wifi等,可针对用户人群所处的网络环境,针对性开发流量节省方式,或线下活动的wifi协理等;应用终端可做到互联网状态更迭及时上报;

(六)
GPS地址:通过应用端得到GPS地址授权获得,用于分析区别地方人群的应用习惯,有利于绘制用户人群画像;

(七) 用户ID:终端用户的唯一身份标识;

(八)
触发时间:应用/事件触发时间,依据时间维度来分析某页面/事件等数据音讯;

③ 、前端埋点方案选型和前端上报方案设计

先是章中牵线了前者所急需监听的音讯,在第1章中介绍了前者埋点的宽泛格局,本文来依据供给,来定制我们的埋点和反映方案。

2.2.2 总计质量指标

可以动用Navigation.timing
总括到的时间数额来测算一些页面品质指标,比如DNS查询耗时、白屏时间、domready等等。如下:

  • DNS查询耗时 = domainLookupEnd – domainLookupStart
  • TCP链接耗费时间 = connectEnd – connectStart
  • request请求耗费时间 = responseEnd – responseStart
  • 解析dom树耗时 = domComplete – domInteractive
  • 白屏时间 = domloadng – fetchStart
  • domready时间 = domContentLoadedEventEnd – fetchStart
  • onload时间 = loadEventEnd – fetchStart

Vue捕获越发

在作者的档次中就遇上这么的题材,使用了js-tracker如此的插件来统一开始展览全局的不得了捕获和日志上报,结果发现大家根本捕获不到Vue零件的十一分,查阅资料得知,在Vue中,万分只怕被Vue自身给try ... catch了,不会流传window.onerror事件触发,那么大家怎么把Vue零件中的非凡香港作家联谊会晤捕获呢?

使用Vue.config.errorHandler这样的Vue大局配置,能够在Vue钦点组件的渲染和观看比赛时期未捕获错误的处理函数。这一个处理函数被调用时,可取得错误音信和Vue
实例。

JavaScript

Vue.config.errorHandler = function (err, vm, info) { // handle error //
`info` 是 Vue 特定的错误音信,比如错误所在的生命周期钩子 // 只在
2.2.0+ 可用 }

1
2
3
4
5
Vue.config.errorHandler = function (err, vm, info) {
  // handle error
  // `info` 是 Vue 特定的错误信息,比如错误所在的生命周期钩子
  // 只在 2.2.0+ 可用
}

React中,能够应用ErrorBoundary组件包罗业务组件的情势展开格外捕获,合营React 16.0+新出的componentDidCatch API,可以达成合并的卓殊捕获和日志上报。

JavaScript

class ErrorBoundary extends React.Component { constructor(props) {
super(props); this.state = { hasError: false }; }
componentDidCatch(error, info) { // Display fallback UI this.setState({
hasError: true }); // You can also log the error to an error reporting
service logErrorToMyService(error, info); } render() { if
(this.state.hasError) { // You can render any custom fallback UI return
<h1>Something went wrong.</h1>; } return
this.props.children; } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }
 
  componentDidCatch(error, info) {
    // Display fallback UI
    this.setState({ hasError: true });
    // You can also log the error to an error reporting service
    logErrorToMyService(error, info);
  }
 
  render() {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
}

使用办法如下:

<ErrorBoundary> <MyWidget /> </ErrorBoundary>

1
2
3
<ErrorBoundary>
  <MyWidget />
</ErrorBoundary>

⑤ 、代码埋点的意义与专注tips

在到现在“大数量”时期,任何一家想发展壮大的营业所,在考虑选用第①方SDK数据产品的数据源丢失难点后,都会优先考虑自行建造数据团队进行代码埋点。获取埋点数据,监测并分析数据音信。因而作为产品运维,必须精通代码埋点的有关技术,做到埋点项目标急需描述说清代楚宏观,跟进项目、不断优化、建议分析优化。有如下难题需注意:

1.显眼所需数据内容,尽也许发挥清楚每二个点击/页面所需监测的多少。不然,失之毫厘谬以千里。举个栗子:

对于电商户业,监测搜索转化率最为日常不过。若在检索筛选页要求申报搜索参数,实际研究开发可由服务端依照前端接口请求,在接口直接获得参数,无须让动用进行汇报;若需获取的是由该搜索筛选页触发进入详情页,应用端在商品详情页上报搜索参数。二者就大有两样,服务端获取的探寻参数并非实际转化参数(后者获得),大概发生用户对寻找结果不满足而结尾未变异转化的图景。因而须要相互数据开始展览纵向相比。

简而言之,获取每三个数量,须描述清细节,研究开发公司才能对其有针对性的、最优处理方案。

2.向服务端明显表明每种指标的详细定义是什么,定义不清、不明,将招致最后数额解析结果的正确与否。比如最普遍的PV(页面浏览量),不一致的概念对终极后台展现的结果不相同,对于用户进入该页面计为浏览量加一,大概用户进入该页,停留时间长度超过5s计为浏览量加一,不一样定义格局,就会有分歧的PV结果。

3.明显各上下级页面的埋点是或不是覆盖完全,若觉察页面离开应用占比极高:极有也许是该页面的下一流页面未实行埋点,导致没有数量报告,服务端分析为离开应用。若发现了漏埋点的情形,尽管能在更新版本中补充,但老版本的数额就永远丢失。所以在埋点规划时,产品运行确定保证埋点事项无遗漏。

(1)监察和控制数据

先是大家供给鲜爱他美个产品或然网页,普遍必要监控和反馈的数据。监察和控制的分为多个阶段:用户进入网页首页、用户在网页内部交互和彼其中报错。每三个等级供给监察和控制和上报的数码如下图所示:

澳门葡京 10

2.2.3 Resource timing API

Resource timing
API是用来计算静态财富相关的光阴信息,详细的始末请参考W3C Resource
timing。这里大家只介绍performance.getEntries办法,它能够获取页面中每种静态财富的伏乞,如下:
澳门葡京 11

能够观察performance.getEntries归来七个数组,数组的各样成分代表对应的静态能源的消息,比如上海体育场面突显的第3个成分对应的财富类型initiatorType是图片img,请求花费的年月就是duration的值。

有关Resource timing API的应用意况,感兴趣的同班能够深刻钻研。

天性监控

六、其他

(1) 个人运用过的第①方数据产品体验

(一)
Umeng,Ali旗下的多少解析产品,通用性功效均有覆盖,在一些特定页面上有缺点和失误,定制化弱,适合初创起步的集团应用。

(二) 谷歌(Google)Analytics,个人使用体验较好,对民用网页、应用所需的多少埋点都能满意,对数码结果呈现较为喜欢,缺点是需翻墙查看;

(三)
神策数据。位于Hong Kong的神策公司,可遵照卖家布局一定服务器,针对特性化定制,并且有对应业务员、开发工程师进行集团一对接二连三接,服务体验较为精美;但数据解析后台非做事范围内,未详细体验、探究过;

(四)
诸葛io,国内抢先、先行的数量解析公司,2011年是国内首家最早推出无埋点方案,但有运行朋友说丢包较为严重,未认可翔实与否。

其余较为盛名的数据产品:TalkingData、Mixpanel未利用过,希望有大神分享,或之后选取后补偿。

最终的嘱咐,数据埋点团队自然要留好数据埋点的行业内部定义文书档案,若发生集体埋点相关老板离职,就会形成大坑。

Ps:别的思考问题整理如下:

(1) 为啥上报的多少颗粒级最好是“原子”最小化上报而非关系链上报?

就算关乎链上报对于还原用户的真实性操作十二分便宜,服务端依照用户访问的日子体系,将事件串联,一步步剖析,对于涉嫌跳转挖掘分外利于;但对于飞快迭代的行使产品,一旦产品有关逻辑变动,则兼具事情分析(服务端)、逻辑关系(前端)须重写,对于前端-服务端都将是了不起的人工投入,以及新老版本的多少涉嫌链争持难点。

(2) 供给有特别管事人短期且平静对代码埋点情势展开“买单”

就算数据开始展览埋点,且产品运转形成数据量化结果、以多少驱动决定的习惯后,则必须举办不断维护。因为数量埋点研发团队,需开支较高的人力能源;测试点位时,必要完整覆盖性测试,确认保证无遗漏。

(2)埋点方案

在实际项目初级中学结束学业生升学考试虑到上报数据的灵敏定制,以及收缩数量传输和服务器的下压力,在所需埋点处不多的景色下,常用的格局是代码埋点。

以用户进入首页为例,大家在首页渲染完结后会发送事件类型和品种相关的多少给server端,告知首页的监察音讯。

澳门葡京 12

2.3 参考资料

  1. Facebook测速方案;
  2. Measuring Page Load Speed with Navigation
    Timing;
  3. 前者数据之美 —
    基础篇;
  4. 7
    天塑造前端品质监察和控制系统;
  5. phantomjs ;
  6. 前者相关数据监察和控制;
  7. 研讨首屏时间?你先要知道这几点细节

最简易的性质监察和控制

最普遍的本性监察和控制供给则是急需大家总计用户从上马请求页面到持有DOM要素渲染完结的时日,也便是俗称的首屏加载时间,DOM提供了这一接口,监听documentDOMContentLoaded事件与windowload事件可总结页面首屏加载时间即怀有DOM渲染时间:

<!DOCTYPE html> <html> <head>
<title></title> <script type=”text/javascript”> //
记录页面加载初阶时间 var timerStart = Date.now(); </script>
<!– 加载静态财富,如样式财富 –> </head> <body>
<!– 加载静态JS财富 –> <script type=”text/javascript”>
document.add伊夫ntListener(‘DOMContentLoaded’, function() {
console.log(“DOM 挂载时间: “, Date.now() – timerStart); // 质量日志上报
}); window.add伊芙ntListener(‘load’, function() {
console.log(“全数能源加载成功时间: “, Date.now()-timerStart); //
品质日志上报 }); </script> </body> </html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html>
<head>
  <title></title>
  <script type="text/javascript">
    // 记录页面加载开始时间
    var timerStart = Date.now();
  </script>
  <!– 加载静态资源,如样式资源 –>
</head>
<body>
  <!– 加载静态JS资源 –>
  <script type="text/javascript">
    document.addEventListener(‘DOMContentLoaded’, function() {
      console.log("DOM 挂载时间: ", Date.now() – timerStart);
      // 性能日志上报
    });
    window.addEventListener(‘load’, function() {
      console.log("所有资源加载完成时间: ", Date.now()-timerStart);
      // 性能日志上报
    });
  </script>
</body>
</html>

对于使用框架,如Vue或者说React,组件是异步渲染然后挂载到DOM的,在页面开始化时并不曾太多的DOM节点,能够参见下文有关首屏时间采访自动化的缓解方案来对渲染时间开始展览行贿。

推介阅读:

(个人在简书上觉得较好的稿子,以及一些小说内容有所参照)

从0入门篇:http://www.jianshu.com/p/0a9263ea9671

采取机理篇:http://www.jianshu.com/p/69859d580354(建议有代码基础或电脑机理基础看,对于领悟埋点达成原理很受用)

可视化埋点的流程呈现、便于通晓:http://www.jianshu.com/p/c2cb80a342c2

无埋点利益:http://www.jianshu.com/p/6f47fc648e69

可看下无埋点机理,以及询问iOS的runtime机制

iOS的runtime机理:http://www.jianshu.com/p/98f39c4d0df8

http://www.jianshu.com/p/69859d580354

简言之可理解为,runtime机制正是在利用中事件都会调用的方法中流入上报数据的埋点代码,知晓该点便于明白作品中的内容。

(3)上报周期和汇报数据类型

若果埋点的风浪不是诸多,上报能够随时实行,比如监察和控制用户的互相事件,能够在用户触发事件后,登时上报用户所接触的风云类型。假使埋点的轩然大波较多,只怕说网页内部交互频繁,能够通过本地存款和储蓄的点子先缓存上报消息,然后定期汇报。

随之来显明要求埋点上报的数码,上报的新闻蕴涵用户个人新闻以及用户作为,首要数据足以分为:

  • who: appid(系统可能选取的id),userAgent(用户的种类、互连网等音讯)
  • when: timestamp(上报的时光戳)
  • from where:
    currentUrl(用户眼下url),fromUrl(从哪1个页面跳转到当前页面),type(上报的事件类型),element(触发上报事件的要素)
  • what:
    上报的自定义扩大数据data:{},扩大数据中得以按供给定制,比如含有uid等音讯

上报数据的靶子为:

{ —————-上报接口本身提供——————– currentUrl,
fromUrl, timestamp, userAgent:{ os, netWord, }
—————-业务代码配置和自定义上报数据———— type, appid,
element, data:{ uid, uname } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{  
    —————-上报接口本身提供——————–
    currentUrl,  
    fromUrl,
    timestamp,
    userAgent:{
       os,
       netWord,
    }
    —————-业务代码配置和自定义上报数据————
    type,
    appid,
    element,
    data:{
        uid,
        uname
    }
}
 

3. JavaScript代码相当监察和控制

JavaScript分外一般有两方面:语法错误运营时不当。二种错误的捕获和处理格局差异,从而影响具体的方案选型。经常来说,处理JS非凡的方案有三种:try...catch捕获
window.onerror破获。以下就三种方案分别分析各自的高低。

即便语法错误本应有在开发构建阶段选用测试工具制止,但难免会有马失前蹄安插到线上的时候。

performance

不过上述时间的监督过于简短,例如大家想总括文档的互连网加载耗时、解析DOM的耗费时间与渲染DOM的耗费时间,就不太好办到了,所幸的是浏览器提供了window.performance接口,具体可知MDN文档

澳门葡京 13

差不离全部浏览器都匡助window.performance接口,下边来看望在控制台打字与印刷window.performance能够博得些什么:

澳门葡京 14

能够看到,window,performance重庆大学不外乎有memorynavigationtiming以及timeOriginonresourcetimingbufferfull方法。

  • navigation指标提供了在钦命的时间段里发出的操作相关音讯,包涵页面是加载依然刷新、发生了多少次重定向等等。
  • timing目的涵盖延迟相关的属性音信。那是我们页面加载品质优化要求中任重(Ren Zhong)而道远反映的相关音信。
  • memoryChrome累加的2个非标准化准增添,那么些天性提供了二个得以获取到核心内部存款和储蓄器使用状态的靶子。在其余浏览器应该考虑到这几个API的同盟处理。
  • timeOrigin则赶回品质衡量起来时的小运的高精度时间戳。如图所示,精确到了小数点后几个人。
  • onresourcetimingbufferfull情势,它是二个在resourcetimingbufferfull事件触发时会被调用的event handler。这一个事件当浏览器的财富时间质量缓冲区已满时会触发。能够经过监听这一事变触发来预估页面crash,总结页面crash可能率,以便前期的品质优化,如下示例所示:
JavaScript

function buffer\_full(event) { console.log("WARNING: Resource Timing
Buffer is FULL!"); performance.setResourceTimingBufferSize(200); }
function init() { // Set a callback if the resource buffer becomes
filled performance.onresourcetimingbufferfull = buffer\_full; }
&lt;body onload="init()"&gt;

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f00bfee161383152889-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f00bfee161383152889-2">
2
</div>
<div class="crayon-num" data-line="crayon-5b8f00bfee161383152889-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f00bfee161383152889-4">
4
</div>
<div class="crayon-num" data-line="crayon-5b8f00bfee161383152889-5">
5
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f00bfee161383152889-6">
6
</div>
<div class="crayon-num" data-line="crayon-5b8f00bfee161383152889-7">
7
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f00bfee161383152889-8">
8
</div>
<div class="crayon-num" data-line="crayon-5b8f00bfee161383152889-9">
9
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f00bfee161383152889-1" class="crayon-line">
function buffer_full(event) {
</div>
<div id="crayon-5b8f00bfee161383152889-2" class="crayon-line crayon-striped-line">
  console.log(&quot;WARNING: Resource Timing Buffer is FULL!&quot;);
</div>
<div id="crayon-5b8f00bfee161383152889-3" class="crayon-line">
  performance.setResourceTimingBufferSize(200);
</div>
<div id="crayon-5b8f00bfee161383152889-4" class="crayon-line crayon-striped-line">
}
</div>
<div id="crayon-5b8f00bfee161383152889-5" class="crayon-line">
function init() {
</div>
<div id="crayon-5b8f00bfee161383152889-6" class="crayon-line crayon-striped-line">
  // Set a callback if the resource buffer becomes filled
</div>
<div id="crayon-5b8f00bfee161383152889-7" class="crayon-line">
  performance.onresourcetimingbufferfull = buffer_full;
</div>
<div id="crayon-5b8f00bfee161383152889-8" class="crayon-line crayon-striped-line">
}
</div>
<div id="crayon-5b8f00bfee161383152889-9" class="crayon-line">
&lt;body onload=&quot;init()&quot;&gt;
</div>
</div></td>
</tr>
</tbody>
</table>

(4)埋点和报告举例

咱俩上述报首屏加载事件为例,DOM提供了document的DOMContentLoaded事件来监听dom挂载,提供了window的load事件来监听页面全数能源加载渲染落成。

<script type=”text/javascript”> var start=Date.now();
document.addEventListener(‘DOMContentLoaded’, function() { fetch(‘some
api’,{ type:’dom complete’, data:{ domCompletedTime:Date.now()-start }
}) }); window.addEventListener(‘load’, function() { fetch(‘some api’,{
type:’load complete’, data:{ LoadCompletedTime:Date.now()-start } }) });
</script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script type="text/javascript">
  var start=Date.now();
  document.addEventListener(‘DOMContentLoaded’, function() {
     fetch(‘some api’,{
         type:’dom complete’,
         data:{
           domCompletedTime:Date.now()-start
         }
     })
  });
  window.addEventListener(‘load’, function() {
     fetch(‘some api’,{
         type:’load complete’,
         data:{
           LoadCompletedTime:Date.now()-start
         }
     })
  });
</script>

3.1 try...catch捕获

那种方案需求开发人士在编辑代码的时候,在预估有丰硕产生的代码段使用try...catch,在发出卓殊时将卓殊音信发送给接口:

try{
//可能发生异常的代码段
}catch(e){
//将异常信息发送服务端
}

try...catch的长处是足以细化到每一种代码块,并且能够自定义错误消息以便总括。

实际到上文提到的二种js万分,try...catch不知所措捕获语法错误,当遭逢语法错误时,浏览器依旧会抛出荒唐Uncaught SyntaxError,然则不会被破获,不会走进catch的代码块内。

其它,假若try代码块中有回调函数也不会被捕获,比如:

try{
var btn = $('#btn');
    btn.on('click',function(){
        //throw error
    });
}catch(e){}

上述代码中btn的监听函数里抛出的11分不可能被外层的catch捕获到,必须额奶罩一层:

try{
var btn = $('#btn');
    btn.on('click',function(){
        try{
            //throw error
        }catch(e){}
    });
}catch(e){}

汇总,try...catch方案的布局卓殊复杂,倘诺人工陈设除了须要大量的工作量,还跟开发人士的力量和经历有关。要是借助理编辑译工具安排(比如fis),那每种代码块都套一层try...catch也是老大难看的同时简单引发部分不得预估的题材。

算算网站质量

使用performancetiming属性,能够获得页面质量相关的数目,这里在无数文章都有涉嫌有关使用window.performance.timing笔录页面性能的稿子,例如alloyteam团组织写的初探
performance –
监控网页与程序质量,对于timing的各样品质含义,能够依靠摘自此文的下图精晓,以下代码摘自此文作为计量网站质量的工具函数参考:

澳门葡京 15

JavaScript

// 获取 performance 数据 var performance = { // memory
是非标准化准属性,只在 Chrome 有 // 财富难题:笔者有个别许内部存款和储蓄器 memory: {
usedJSHeapSize: 16一千00, // JS
对象(包罗V8引擎内部对象)占用的内部存款和储蓄器,一定小于 totalJSHeapSize
totalJSHeapSize: 35一千00, // 可选用的内部存款和储蓄器 jsHeapSizeLimit: 79三千000 //
内部存款和储蓄器大小限制 }, // 农学难点:我从哪个地方来? navigation: { redirectCount:
0, // 假如有重定向的话,页面通过一遍重定向跳转而来 type: 0 // 0 即
TYPE_NAVIGATENEXT 符合规律进入的页面(非刷新、非重定向等) // 1 即
TYPE_RELOAD 通过 window.location.reload() 刷新的页面 // 2 即
TYPE_BACK_FOCRUISERWACR-VD 通过浏览器的迈入后退按钮进入的页面(历史记录) //
255 即 TYPE_UNDEFINED 非上述办法进入的页面 }, timing: { //
在同三个浏览器上下文中,前多少个网页(与当前页面不肯定同域)unload
的日子戳,如若无前1个网页 unload ,则与 fetchStart 值相等
navigationStart: 144111269壹玖叁贰, // 前二个网页(与近来页面同域)unload
的时光戳,即便无前一个网页 unload 恐怕前叁个网页与当前页面差别域,则值为
0 unload伊芙ntStart: 0, // 和 unload伊芙ntStart 相对应,重回前三个网页
unload 事件绑定的回调函数执行达成的岁月戳 unload伊芙ntEnd: 0, // 第四个HTTP 重定向发生时的小时。有跳转且是同域名内的重定向才算,不然值为 0
redirectStart: 0, // 最后一个 HTTP
重定向实现时的时刻。有跳转且是同域名内部的重定向才算,不然值为 0
redirectEnd: 0, // 浏览器准备好利用 HTTP
请求抓取文书档案的日子,那爆发在检讨本地缓存从前 fetchStart: 1441112692155,
// DNS 域名询问初始的时光,假使运用了地面缓存(即无 DNS
查询)或持久连接,则与 fetchStart 值相等 domainLookupStart:
1441112692155, // DNS 域名询问达成的年月,若是利用了当地缓存(即无 DNS
查询)或持久连接,则与 fetchStart 值相等 domainLookupEnd: 1441112692155,
// HTTP(TCP) 开端树立连接的时间,要是是从头到尾连接,则与 fetchStart
值相等 //
注意若是在传输层发生了错误且再次建立连接,则那里显得的是新创制的连年起来的日子
connectStart: 1441112692155, // HTTP(TCP)
完毕建立连接的时光(完毕握手),假如是持久连接,则与 fetchStart 值相等
//
注意若是在传输层发生了不当且重新创建连接,则那里突显的是新建立的连天成功的年月
// 注意那里握手结束,蕴涵平安连接建立完结、SOCKS 授权通过 connectEnd:
1441112692155, // HTTPS 连接起来的时间,假设不是安全连接,则值为 0
secureConnectionStart: 0, // HTTP
请求读取真实文书档案起始的时日(完毕建立连接),包涵从当地读取缓存 //
连接错误重连时,那里显示的也是新创设连接的光阴 requestStart:
1441112692158, // HTTP
起先接受响应的时光(获取到第②个字节),包蕴从本土读取缓存
responseStart: 1441112692686, // HTTP
响应全体吸收实现的大运(获取到最终三个字节),包含从地点读取缓存
responseEnd: 1441112692687, // 初步解析渲染 DOM 树的岁月,此时
Document.readyState 变为 loading,并将抛出 readystatechange 相关事件
domLoading: 1441112692690, // 完毕解析 DOM 树的时间,Document.readyState
变为 interactive,并将抛出 readystatechange 相关事件 // 注意只是 DOM
树解析完毕,那时候并不曾起来加载网页内的资源 domInteractive:
1441112693093, // DOM 解析完结后,网页国内资本源加载开头的光阴 // 在
DOMContentLoaded 事件抛出前发出 domContentLoaded伊夫ntStart:
1441112693093, // DOM 解析完毕后,网页国内资本源加载成功的年华(如 JS
脚本加载执行达成) domContentLoaded伊夫ntEnd: 1441112693101, // DOM
树解析实现,且能源也准备稳妥的年月,Document.readyState 变为
complete,并将抛出 readystatechange 相关事件 domComplete: 1441112693214,
// load 事件发送给文书档案,也即 load 回调函数开头实践的时间 //
注意假诺没有绑定 load 事件,值为 0 load伊芙ntStart: 1441112693214, //
load 事件的回调函数执行达成的时日 load伊芙ntEnd: 1441112693215 //
字母顺序 // connectEnd: 1441112692155, // connectStart: 1441112692155,
// domComplete: 1441112693214, // domContentLoaded伊芙ntEnd:
1441112693101, // domContentLoaded伊夫ntStart: 1441112693093, //
domInteractive: 1441112693093, // domLoading: 1441112692690, //
domainLookupEnd: 1441112692155, // domainLookupStart: 1441112692155, //
fetchStart: 1441112692155, // load伊芙ntEnd: 1441112693215, //
load伊芙ntStart: 1441112693214, // navigationStart: 144111269一九三五, //
redirectEnd: 0, // redirectStart: 0, // requestStart: 1441112692158, //
responseEnd: 1441112692687, // responseStart: 1441112692686, //
secureConnectionStart: 0, // unload伊芙ntEnd: 0, // unload伊芙ntStart: 0 }
};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// 获取 performance 数据
var performance = {  
    // memory 是非标准属性,只在 Chrome 有
    // 财富问题:我有多少内存
    memory: {
        usedJSHeapSize:  16100000, // JS 对象(包括V8引擎内部对象)占用的内存,一定小于 totalJSHeapSize
        totalJSHeapSize: 35100000, // 可使用的内存
        jsHeapSizeLimit: 793000000 // 内存大小限制
    },
    //  哲学问题:我从哪里来?
    navigation: {
        redirectCount: 0, // 如果有重定向的话,页面通过几次重定向跳转而来
        type: 0           // 0   即 TYPE_NAVIGATENEXT 正常进入的页面(非刷新、非重定向等)
                          // 1   即 TYPE_RELOAD       通过 window.location.reload() 刷新的页面
                          // 2   即 TYPE_BACK_FORWARD 通过浏览器的前进后退按钮进入的页面(历史记录)
                          // 255 即 TYPE_UNDEFINED    非以上方式进入的页面
    },
    timing: {
        // 在同一个浏览器上下文中,前一个网页(与当前页面不一定同域)unload 的时间戳,如果无前一个网页 unload ,则与 fetchStart 值相等
        navigationStart: 1441112691935,
        // 前一个网页(与当前页面同域)unload 的时间戳,如果无前一个网页 unload 或者前一个网页与当前页面不同域,则值为 0
        unloadEventStart: 0,
        // 和 unloadEventStart 相对应,返回前一个网页 unload 事件绑定的回调函数执行完毕的时间戳
        unloadEventEnd: 0,
        // 第一个 HTTP 重定向发生时的时间。有跳转且是同域名内的重定向才算,否则值为 0
        redirectStart: 0,
        // 最后一个 HTTP 重定向完成时的时间。有跳转且是同域名内部的重定向才算,否则值为 0
        redirectEnd: 0,
        // 浏览器准备好使用 HTTP 请求抓取文档的时间,这发生在检查本地缓存之前
        fetchStart: 1441112692155,
        // DNS 域名查询开始的时间,如果使用了本地缓存(即无 DNS 查询)或持久连接,则与 fetchStart 值相等
        domainLookupStart: 1441112692155,
        // DNS 域名查询完成的时间,如果使用了本地缓存(即无 DNS 查询)或持久连接,则与 fetchStart 值相等
        domainLookupEnd: 1441112692155,
        // HTTP(TCP) 开始建立连接的时间,如果是持久连接,则与 fetchStart 值相等
        // 注意如果在传输层发生了错误且重新建立连接,则这里显示的是新建立的连接开始的时间
        connectStart: 1441112692155,
        // HTTP(TCP) 完成建立连接的时间(完成握手),如果是持久连接,则与 fetchStart 值相等
        // 注意如果在传输层发生了错误且重新建立连接,则这里显示的是新建立的连接完成的时间
        // 注意这里握手结束,包括安全连接建立完成、SOCKS 授权通过
        connectEnd: 1441112692155,
        // HTTPS 连接开始的时间,如果不是安全连接,则值为 0
        secureConnectionStart: 0,
        // HTTP 请求读取真实文档开始的时间(完成建立连接),包括从本地读取缓存
        // 连接错误重连时,这里显示的也是新建立连接的时间
        requestStart: 1441112692158,
        // HTTP 开始接收响应的时间(获取到第一个字节),包括从本地读取缓存
        responseStart: 1441112692686,
        // HTTP 响应全部接收完成的时间(获取到最后一个字节),包括从本地读取缓存
        responseEnd: 1441112692687,
        // 开始解析渲染 DOM 树的时间,此时 Document.readyState 变为 loading,并将抛出 readystatechange 相关事件
        domLoading: 1441112692690,
        // 完成解析 DOM 树的时间,Document.readyState 变为 interactive,并将抛出 readystatechange 相关事件
        // 注意只是 DOM 树解析完成,这时候并没有开始加载网页内的资源
        domInteractive: 1441112693093,
        // DOM 解析完成后,网页内资源加载开始的时间
        // 在 DOMContentLoaded 事件抛出前发生
        domContentLoadedEventStart: 1441112693093,
        // DOM 解析完成后,网页内资源加载完成的时间(如 JS 脚本加载执行完毕)
        domContentLoadedEventEnd: 1441112693101,
        // DOM 树解析完成,且资源也准备就绪的时间,Document.readyState 变为 complete,并将抛出 readystatechange 相关事件
        domComplete: 1441112693214,
        // load 事件发送给文档,也即 load 回调函数开始执行的时间
        // 注意如果没有绑定 load 事件,值为 0
        loadEventStart: 1441112693214,
        // load 事件的回调函数执行完毕的时间
        loadEventEnd: 1441112693215
        // 字母顺序
        // connectEnd: 1441112692155,
        // connectStart: 1441112692155,
        // domComplete: 1441112693214,
        // domContentLoadedEventEnd: 1441112693101,
        // domContentLoadedEventStart: 1441112693093,
        // domInteractive: 1441112693093,
        // domLoading: 1441112692690,
        // domainLookupEnd: 1441112692155,
        // domainLookupStart: 1441112692155,
        // fetchStart: 1441112692155,
        // loadEventEnd: 1441112693215,
        // loadEventStart: 1441112693214,
        // navigationStart: 1441112691935,
        // redirectEnd: 0,
        // redirectStart: 0,
        // requestStart: 1441112692158,
        // responseEnd: 1441112692687,
        // responseStart: 1441112692686,
        // secureConnectionStart: 0,
        // unloadEventEnd: 0,
        // unloadEventStart: 0
    }
};

 

JavaScript

// 计算加载时间 function getPerformance提姆ing() { var performance =
window.performance; if (!performance) { // 当前浏览器不支持console.log(‘你的浏览器不扶助 performance 接口’); return; } var t =
performance.timing; var times = {}; //【主要】页面加载成功的年华
//【原因】那差不多代表了用户等待页面可用的流年 times.loadPage =
t.load伊夫ntEnd – t.navigationStart; //【主要】解析 DOM 树结构的年月
//【原因】反省下您的 DOM 树嵌套是不是太多了! times.domReady =
t.domComplete – t.responseEnd; //【首要】重定向的小时//【原因】拒绝重定向!比如, 就不应当写成
times.redirect = t.redirectEnd – t.redirectStart;
//【重要】DNS 查询时间 //【原因】DNS
预加载做了么?页面内是还是不是选用了太多区别的域著名制片人致域名查询的时刻太长?
// 可选拔 HTML5 Prefetch 预查询 DNS ,见:[HTML5
prefetch]()
times.lookupDomain = t.domainLookupEnd – t.domainLookupStart;
//【主要】读取页面第②个字节的年月
//【原因】那足以明白为用户获得您的能源占用的时辰,加异地机房了么,加CDN
处理了么?加带宽了么?加 CPU 运算速度了么? // TTFB 即 提姆e To First
Byte 的趣味 //
维基百科: times.ttfb
= t.responseStart – t.navigationStart; //【主要】内容加载成功的时辰//【原因】页面内容通过 gzip 压缩了么,静态资源 css/js 等压缩了么?
times.request = t.responseEnd – t.requestStart; //【主要】执行 onload
回调函数的时刻 //【原因】是否太多不要求的操作都放到 onload
回调函数里进行了,考虑过延迟加载、按需加载的策略么? times.load伊芙nt =
t.load伊夫ntEnd – t.load伊夫ntStart; // DNS 缓存时间 times.appcache =
t.domainLookupStart – t.fetchStart; // 卸载页面包车型大巴时光 times.unload伊夫nt
= t.unload伊芙ntEnd – t.unload伊夫ntStart; // TCP 建立连接成功握手的年华
times.connect = t.connectEnd – t.connectStart; return times; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// 计算加载时间
function getPerformanceTiming() {
    var performance = window.performance;
    if (!performance) {
        // 当前浏览器不支持
        console.log(‘你的浏览器不支持 performance 接口’);
        return;
    }
    var t = performance.timing;
    var times = {};
    //【重要】页面加载完成的时间
    //【原因】这几乎代表了用户等待页面可用的时间
    times.loadPage = t.loadEventEnd – t.navigationStart;
    //【重要】解析 DOM 树结构的时间
    //【原因】反省下你的 DOM 树嵌套是不是太多了!
    times.domReady = t.domComplete – t.responseEnd;
    //【重要】重定向的时间
    //【原因】拒绝重定向!比如,http://example.com/ 就不该写成 http://example.com
    times.redirect = t.redirectEnd – t.redirectStart;
    //【重要】DNS 查询时间
    //【原因】DNS 预加载做了么?页面内是不是使用了太多不同的域名导致域名查询的时间太长?
    // 可使用 HTML5 Prefetch 预查询 DNS ,见:[HTML5 prefetch](http://segmentfault.com/a/1190000000633364)            
    times.lookupDomain = t.domainLookupEnd – t.domainLookupStart;
    //【重要】读取页面第一个字节的时间
    //【原因】这可以理解为用户拿到你的资源占用的时间,加异地机房了么,加CDN 处理了么?加带宽了么?加 CPU 运算速度了么?
    // TTFB 即 Time To First Byte 的意思
    // 维基百科:https://en.wikipedia.org/wiki/Time_To_First_Byte
    times.ttfb = t.responseStart – t.navigationStart;
    //【重要】内容加载完成的时间
    //【原因】页面内容经过 gzip 压缩了么,静态资源 css/js 等压缩了么?
    times.request = t.responseEnd – t.requestStart;
    //【重要】执行 onload 回调函数的时间
    //【原因】是否太多不必要的操作都放到 onload 回调函数里执行了,考虑过延迟加载、按需加载的策略么?
    times.loadEvent = t.loadEventEnd – t.loadEventStart;
    // DNS 缓存时间
    times.appcache = t.domainLookupStart – t.fetchStart;
    // 卸载页面的时间
    times.unloadEvent = t.unloadEventEnd – t.unloadEventStart;
    // TCP 建立连接完成握手的时间
    times.connect = t.connectEnd – t.connectStart;
    return times;
}

(5)前端埋点系统的内外端通讯加密

在汇报数据的前后端通讯中,须要和server端协商加密机制,利用
OpenSSL库来兑现的加密,OpenSSL已经是3个广阔被使用的加密算法。前端能够利用node的crypto模块。

率先来看hash算法,crypto.createHash()
来创立三个Hash实例,可利用的hash算法如下:

  • md5
  • sha1
  • sha256
  • sha512
  • ripemd160

以sha256算法加密为例:

const str=”123445″;//须要加密的字段 const
hash=crypto.createHash(‘sha256’);//钦命加密算法 hash.update(str);
//通过算法加密相应的字段 const
result=hash.digest(‘hex’);//转化成十六进制

1
2
3
4
5
const str="123445";//需要加密的字段
const hash=crypto.createHash(‘sha256’);//指定加密算法
hash.update(str); //通过算法加密相应的字段
const result=hash.digest(‘hex’);//转化成十六进制
 

3.2 window.onerror捕获

这种艺术不必要开发人士在代码中书写大量的try...catch,通过给window添加onerror监听,在js爆发非凡的时候便能够捕获到错误消息,语法至极和周转格外均可被擒获到。然则window.onerror以此监听非得放在全部js文件在此以前才足以保障能够捕获到持有的不胜音讯。

window.onerror事件的详细消息参考这里。

/**
 * @param {String}  errorMessage   错误信息
 * @param {String}  scriptURL      出错文件的URL
 * @param {Long}    lineNumber     出错代码的行号
 * @param {Long}    columnNumber   出错代码的列号
 * @param {Object}  errorObj       错误信息Object
 */
window.onerror = function(errorMessage, scriptURL, lineNumber,columnNumber,errorObj) { 
    // code..
}

onerror的落实方式各浏览器略有差距,不过前多个参数都以一律的,某个低版本浏览器没有后三个参数。

末尾二个参数errorObj各浏览器实现的水平不雷同,具体可参看这里。

下图是被onerror捕获到的一个充足的求实音信:
澳门葡京 16

汇总,window.onerror方案的帮助和益处是收缩了开发职员的工作量,陈设方便,并且能够捕获语法错误和周转错误。缺点是错误新闻无法自定义,并且errorObj种种浏览器的完结有略微差距,导致需计算的音信有局限性。

日志上报

四 、前端监察和控制结果可视化呈现系统的设计

当后端获得前端上报的音信之后,经过多少解析和拍卖,要求前端可视化的体现数据解析后的结果。

能够在开源中后台系统ant-design-pro的底蕴上开始展览1遍开发,首先要强烈展现音信。体现的音讯包含单个用户和完全选择。

对此单个用户来说须求浮现的监察新闻为:

  • 单个用户,在互相进度中触发各样埋点事件的次数
  • 单个用户,在有个别时间周期内,访问本网页的进口来源
  • 单个用户,在每贰个子页面包车型客车停留时间

对于整个用户必要出示的音讯为:

  • 某一个小时段内网页的PV和UV
  • 全部用户访问网页的装备和操作系统一分配析
  • 某一个光阴段内访问本网页的进口来源分析
  • 成套用户在走访本网页时,在互相进程中触发各类埋点事件的总次数
  • 总体用户在拜访本网页时,网页上报非常的集聚

删选效用集聚:

  • 光阴筛选:提供今天(00点到日前光阴)、本周、本月和全年
  • 用户删选:提供遵照用户id删选出用户作为的总括新闻
  • 设施删选:删选不一致种类的总体展现信息

    1 赞 收藏
    评论

澳门葡京 17

3.3 跨域JS文件尤其的捕获

为了进步web品质,近期多数web产品架构中都有CDN这一环,将能源布置到分化的域名上,丰富利用浏览器的出现请求机制。那么在跨域JS文件中发生特别的时候,onerror监听会捕获到何以新闻吗?请看下图:
澳门葡京 18

唯有三个多少有价值的音信Script error,其余什么音信都并未,为何会如此呢?

大家都知晓浏览器有同源财富限制,常规状态下是力不从心展开跨域请求的。而script、img、iframe标签的src属性是从未有过那种限制的,这也是累累跨域方案的根底。然而正是script标签能够请求到海外的js文件,此文件中的消息也并不能暴光到当下域内,这也是浏览器的本溪措施所致。

那就是说有没有法子获得到国外财富的尤其新闻吗?

事实上很简单,最近得以说基本上全部的web产品对于js/css/image等静态财富都在服务端设置了Access-Control-Allow-Origin: *的响应头,也正是允许跨域请求。在这一个条件下,只要大家在乞求跨域财富的script标签上添加四个crossorigin性子即可:

<script src="http://static.toutiao.com/test.js" crossorigin></script>

那样的话,异域的test.js文件中生出尤其时便能够被当前域的onerror监听捕获到详细的杰出新闻。

独立的日志域名

对于日记上报利用单独的日记域名的指标是幸免对作业造成影响。其一,对于服务器来说,大家自然不指望占用工作服务器的盘算财富,也不期待过多的日志在工作服务器堆积,造成工作服务器的囤积空间不够的事态。其二,我们知道在页面初始化的进度中,会对页面加载时间、PV、UV等数码实行反馈,那么些举报告请示求会和加载业务数据大概是同时刻产生,而浏览器一般会对同一个域名的请求量有并发数的界定,如Chrome会有对并发数为6个的限制。由此供给对日记系统独立设定域名,最小化对页面加载质量造成的影响。

3.4 参考资料

  1. 创设web前端万分监察和控制系统;
  2. 前者代码至极日志收集与监督;
  3. 前者代码至极监察和控制

跨域的题材

对此单身的日志域名,肯定会涉嫌到跨域的题材,选拔的解决方案一般有以下二种:

  • 一种是构造空的Image目的的措施,其原因是请求图片并不关乎到跨域的标题;
JavaScript

var url = 'xxx'; new Image().src = url;

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f00bfee170123843269-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f00bfee170123843269-2">
2
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f00bfee170123843269-1" class="crayon-line">
var url = 'xxx';
</div>
<div id="crayon-5b8f00bfee170123843269-2" class="crayon-line crayon-striped-line">
new Image().src = url;
</div>
</div></td>
</tr>
</tbody>
</table>

  • 利用Ajax上报日志,必须对日记服务器接口开启跨域请求尾部Access-Control-Allow-Origin:*,这里Ajax就并不强制行使GET请求了,即可打败URL长度限制的标题。
JavaScript

if (XMLHttpRequest) { var xhr = new XMLHttpRequest();
xhr.open('post', 'https://log.xxx.com', true); //
上报给node中间层处理 xhr.setRequestHeader('Content-Type',
'application/json'); // 设置请求头
xhr.send(JSON.stringify(errorObj)); // 发送参数 }

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f00bfee174544186263-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f00bfee174544186263-2">
2
</div>
<div class="crayon-num" data-line="crayon-5b8f00bfee174544186263-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f00bfee174544186263-4">
4
</div>
<div class="crayon-num" data-line="crayon-5b8f00bfee174544186263-5">
5
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f00bfee174544186263-6">
6
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f00bfee174544186263-1" class="crayon-line">
if (XMLHttpRequest) {
</div>
<div id="crayon-5b8f00bfee174544186263-2" class="crayon-line crayon-striped-line">
  var xhr = new XMLHttpRequest();
</div>
<div id="crayon-5b8f00bfee174544186263-3" class="crayon-line">
  xhr.open('post', 'https://log.xxx.com', true); // 上报给node中间层处理
</div>
<div id="crayon-5b8f00bfee174544186263-4" class="crayon-line crayon-striped-line">
  xhr.setRequestHeader('Content-Type', 'application/json'); // 设置请求头
</div>
<div id="crayon-5b8f00bfee174544186263-5" class="crayon-line">
  xhr.send(JSON.stringify(errorObj)); // 发送参数
</div>
<div id="crayon-5b8f00bfee174544186263-6" class="crayon-line crayon-striped-line">
}
</div>
</div></td>
</tr>
</tbody>
</table>

在本人的种类中央银行使的是率先种的不二法门,也正是组织空的Image对象,不过大家驾驭对于GET呼吁会有长度的界定,供给确定保障的是呼吁的长短不会超过阈值。

节省响应中央

对此我们汇报日志,其实对于客户端的话,并不要求考虑上报的结果,甚至对于举报战败,我们也不供给在前者做其它交互,所以报告来说,其实采纳HEAD伸手就够了,接口重返空的结果,最大地压缩上报日志造成的财富浪费。

集合反映

就好像于Sprite图的思辨,倘若我们的行使须求申报的日志数量众多,那么有必不可少合并日志实行统一的反映。

消除方案得以是尝尝在用户距离页面恐怕零部件销毁时发送3个异步的POST呼吁来进展申报,可是尝试在卸载(unload)文书档案在此以前向web服务器发送数据。有限帮忙在文书档案卸载时期发送数据平素是二个艰辛。因为用户代理平时会忽视在卸载事件处理器中产生的异步XMLHttpRequest,因为此时曾经会跳转到下一个页面。所以这边是必须设置为一起的XMLHttpRequest请求吗?

JavaScript

window.add伊夫ntListener(‘unload’, logData, false); function logData() {
var client = new XMLHttpRequest(); client.open(“POST”, “/log”, false);
// 第八个参数评释是一路的 xhr client.setRequestHeader(“Content-Type”,
“text/plain;charset=UTF-8”); client.send(analyticsData); }

1
2
3
4
5
6
7
8
window.addEventListener(‘unload’, logData, false);
 
function logData() {
    var client = new XMLHttpRequest();
    client.open("POST", "/log", false); // 第三个参数表明是同步的 xhr
    client.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
    client.send(analyticsData);
}

运用同步的方式势必会对用户体验造成影响,甚至会让用户感受到浏览器卡死感到,对于产品而言,体验十一分不好,通过查阅MDN文档,能够应用sendBeacon()方法,将会使用户代理在有机遇时异步地向服务器发送数据,同时不会延迟页面包车型客车卸载或影响下一导航的载入质量。那就一蹴即至了提交分析数据时的有着的标题:使它可信,异步并且不会影响下一页面的加载。其余,代码实际上还要比其余技术不难!

下边包车型大巴事例体现了三个辩解上的总括代码情势——通过使用sendBeacon()方法向服务器发送数据。

JavaScript

window.addEventListener(‘unload’, logData, false); function logData() {
navigator.sendBeacon(“/log”, analyticsData); }

1
2
3
4
5
window.addEventListener(‘unload’, logData, false);
 
function logData() {
    navigator.sendBeacon("/log", analyticsData);
}

小结

用作前端开发者而言,要对产品保持敬畏之心,时刻保持对品质追求极致,对那三个不可忍受的态度。前端的习性监察和控制与丰富申报显得越发重庆大学。

代码难免有标题,对于丰裕能够运用window.onerror或者addEventListener的方法丰裕全局的不行捕获侦听函数,但只怕利用那种格局不能够正确捕获到不当:对于跨域的台本,需求对script标签扩大叁个crossorigin=”anonymous”;对于生产环境打包的代码,不可能正明确位到那些发生的行数,可以使用source-map来化解;而对此利用框架的场地,供给在框架统一的要命捕获处埋点。

而对于品质的监察,所幸的是浏览器提供了window.performance API,通过这么些API,很轻便地获得到当下页面性能相关的数额。

而那一个卓殊和属性数据怎样反馈呢?一般说来,为了制止对工作发生的影响,会单独创建日志服务器和日志域名,但对于分裂的域名,又会发生跨域的难题。大家得以因此组织空的Image对象来缓解,亦或许通过设定跨域请求尾部Access-Control-Allow-Origin:*来缓解。其它,若是申报的属性和日志数据高频触发,则足以在页面unload时统一举报,而unload时的异步请求又只怕会被浏览器所忽视,且不能够改为一起请求。此时navigator.sendBeacon API可算帮了我们大忙,它可用于通过HTTP将少量数据异步传输到Web服务器。而忽略页面unload时的影响。

1 赞 1 收藏
评论

澳门葡京 19

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website