热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

让前端监控数据收集更高效

跟着营业的疾速生长,我们对临盆环境下的题目感知才能愈来愈关注。作为间隔用户近来的一层,前端的表现是不是牢靠、稳固、好用,很大程度上决议着用户对悉数产物的体验和感觉。因而,关于前端的

跟着营业的疾速生长,我们对临盆环境下的题目感知才能愈来愈关注。作为间隔用户近来的一层,前端的表现是不是牢靠、稳固、好用,很大程度上决议着用户对悉数产物的体验和感觉。因而,关于前端的监控不容忽视。

搭建一套前端监控平台须要斟酌的方面许多,比方数据网络、埋点情势、数据处置惩罚和剖析、报警以及监控平台在详细营业中的应用等等。在这一切环节中,正确、完整、周全的数据网络是一切的条件,也为后续的用户精细化运营供应基础。

前端手艺的一日千里给数据网络也带来了变化和应战,传统的手工办理情势已不能满足需求。如安在新的手艺背景下让前端数据网络事情越发完美、高效,是本文议论的重点。

前端监控数据网络

在网络数据之前,起首要斟酌网络什么样的数据。我们重点关注两类数据,一类是与用户体验相干的,如首屏时刻、文件加载时刻、页面机能等;别的是协助我们实时感知产物上线后是不是涌现异常的,比方资本毛病、API 相应时刻等。详细来讲,我们对前端的数据网络详细主要分为:

  • 路由切换 (href、hashchange、pushState)
  • JsError
  • 机能 (performance)
  • 资本毛病
  • API
  • 日记上报

路由切换

Vue、React、Angular 等前端手艺的疾速生长使单页面应用盛行。我们都晓得,传统的页面应用是用一些超链接来完成页面切换和跳转的,而单页面应用是应用各自的路由体系来治理前端的每个页面切换,比方 vue-router、react-router 等,跳转时仅革新部分资本 ,js、css 等公共资本只须要加载一次,这就使传统网页进入脱离的体式格局只要第一次翻开能被纪录。单页应用后续一切路由切换的体式格局有两种,一种是 Hash,一种是 HTML5 推出的 History API。

1. href

href 为页面初始化的第一次进入,这里只须要纯真上报「进入页面」事宜即可。

2. hashchange

Hash 路由一个显著的标志是带有「 # 」。Hash 的上风是兼容性更好,但题目在于 URL 中一向存在「 # 」并不雅观。我们主要经由过程监听 URL 中的 hashchange 来捕捉详细的 hash 值举行检测。

window.addEventListener('hashchange', function() {
    // 上报【进入页面】事宜
}, true)

须要注重的是,在新版 vue-router 中假如浏览器支撑 history,纵然 mode 挑选 hash 也会优先挑选 history 情势,虽然表现情势临时照样 # 号,但现实上是模仿的,所以万万不要以为自身在 mode 挑选了hash 就肯定会是 hash。

3. History API

History 应用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 要领举行路由切换,是现在主流的无革新切换路由体式格局。与 hashchange 只能转变 # 背面的代码片断比拟,History API (pushState、replaceState) 给了前端完整的自在。

PopState 是浏览器返回事宜的回调,然则更新路由的 pushState、replaceState 并没有回调事宜,因而,还须要分别在 history.pushState() 和 history.replaceState() 要领里处置惩罚 URL 的变化。在这里,我们应用到了一种相似 Java 的 AOP 编程头脑,对 pushState 和 replaceState 举行革新。

AOP (Aspect-oriented programming)即面向切面编程,首倡针对一致类题目举行一致处置惩罚。AOP 的中心头脑是让某个模块能够重用,它采纳横向抽取机制,将功用代码从营业逻辑代码中分离出来,扩大功用而不修正源代码,比拟封装来讲断绝得越发完全。

下面引见我们的详细革新体式格局:

// 第一阶段:我们对原生要领举行包装,挪用前实行 dispatchEvent 了一个一样的事宜
function aop (type) {
    var source = window.history[type];
    return function () {
        var event = new Event(type);
        event.arguments = arguments;
        window.dispatchEvent(event);
        var rewrite = source.apply(this, arguments);
        return rewrite;
    };
}
// 第二阶段:将 pushState 和 replaceState 举行基于 AOP 头脑的代码注入
window.history.pushState = aop('pushState');
window.history.replaceState = aop('replaceState'); // 变动路由,不会留下历史纪录
// 第三阶段:捕捉pushState 和 replaceState
window.addEventListener('pushState', function() {
    // 上报【进入页面】事宜
}, true)
window.addEventListener('replaceState', function() {
    // 上报【进入页面】事宜
}, true)

window.history.pushState 现实挪用关联如图:

《让前端监控数据收集更高效》

至此,我们对 pushState、replaceState 革新终了,完成了有效地捕捉路由切换。能够看到,我们在不侵入营业代码的状况下,对 window.history.pushState 举行了扩大,在挪用的同时会主动 dispatchEvent 一个 pushState。

但在这里我们也能看到一个弊病,就是假如 AOP 代办函数发作 JS 毛病,将会阻断后续的挪用关联,使现实的 window.history.pushState 没法被挪用。所以在应用此体式格局的时刻,要对 AOP 代办函数的内容做好完美的 try catch,来防备营业上涌现异常。

*__Tips:想自动捕捉页面停留时刻只须要在下一个进入页面事宜触发时,经由过程上一个页面的办理时刻和当前时刻做差值即可,这时候刻能够上报一个【脱离页面】事宜。

JsError

前端项目中,由于 Javascript 自身是一个弱范例言语,加上浏览器环境的复杂性、网络题目等,很轻易发作毛病。因而做好网页毛病监控,不停优化代码,进步代码健壮性是一项很主要的事情。

JsError 的捕捉能够协助我们剖析和监控线上题目,它与我们在 Chrome 浏览器的调试东西 Console 中看到的内容一致。

1. window.onerror

我们应用 window.onerror 捕捉平常状况下 JS 毛病的异常信息。捕捉 JS 毛病的体式格局有两种,window.onerror 和 window.addEventListener(‘error’)。平常状况下,捕捉 JS 异常不引荐应用 addEventListener(‘error’),主要是由于它没有客栈信息,而且还须要对捕捉到的信息做辨别,由于它会将一切异常信息捕捉到,包含资本加载毛病等。

window.onerror = function (msg, url, lineno, colno, stack) {
    // 上报 【js毛病】事宜
}

2. Uncaught (in promise)

当 Promise 内发作 JS 毛病或许 reject 信息未被营业处置惩罚的状况时,会抛出一个 unhandledrejection,而且这个毛病不会被 window.onerror 以及 window.addEventListener(‘error’)  捕捉,这里须要用特地的 window.addEventListener(‘unhandledrejection’)  举行捕捉处置惩罚:

window.addEventListener('unhandledrejection', function (e) {
    var reg_url = /\(([^)]*)\)/;
    var fileMsg = e.reason.stack.split('\n')[1].match(reg_url)[1];
    var fileArr = fileMsg.split(':');
    var lineno = fileArr[fileArr.length - 2];
    var colno = fileArr[fileArr.length - 1];
    var url = fileMsg.slice(0, -lno.length - cno.length - 2);}, true);
    var msg = e.reason.message;
    // 上报 【js毛病】事宜
}

我们注重到 unhandledrejection 由于继续自 PromiseRejectionEvent,PromiseRejectionEvent 又继续自 Event,所以 msg、url、lineno、colno、stack 以字符串情势放到了 e.reason.stack 中,我们须要剖析出来上述参数来和 onerror 参数对齐,为后续监控平台的目标一致化打下基础。

3. 常见题目

  • “Script error.”

假如涌现捕捉的 msg 悉数为 “Script error.” ,题目在于你的 JS 地点和当前网页不在一致个域下。由于我们要常常在线上的版本做静态资本 CDN 化,会致使常接见的页面跟脚本文件来自差别的域名。这时候假如没有举行分外的设置,浏览器出于平安方面的设想就轻易涌现 “Script error.”。我们能够应用现在盛行的 Webpack 打包东西来处置惩罚此类题目。

// webpack config 设置
// 处置惩罚 html 注入 js 增加跨域标识
plugins: [
    new HtmlWebpackPlugin({
      filename: 'html/index.html',
      template: HTML_PATH,
      attributes: {
        crossorigin: 'anonymous'
      }
    }),
    new HtmlWebpackPluginCrossorigin({
      inject: true
    })
]
// 处置惩罚按需加载的 js 增加跨域标识
output: {
    crossOriginLoading: true
}

  • SourceMap

大部分场景下,临盆环境中的代码都是经由紧缩兼并的,这使得我们捕捉到的毛病很难映照到详细的源码,为我们处理题目带来很大搅扰,这里扼要提出 2 个处理方案的思绪。

临盆环境我们须要增加 sourceMap 设置,这会致使平安隐患,由于如许外网就能够经由过程 sourceMap 举行源码映照。为了下降风险,我们能够经由过程以下体式格局:

  1. 将 sourceMap 天生的 .map 文件设置公司内网接见,下降源码平安风险
  2. 在宣布代码到 CDN 的时刻,将 .map 文件存储到公司内网下

这时候我们已具有了 .map 文件,后续要做的就是经由过程捕捉到的 lineno、colno、url 挪用 mozilla/source-map 库举行源码映照,即可拿到实在的源码毛病信息。

机能

机能目标的猎取相对比较简单,在 onload 以后读取 window.performance 即可,内里包含了机能、内存等信息。这部分内容在许多现有的文章中都有引见,因篇幅所限不在本文做过量睁开,以后在相干主题文章中我们会有相干讨论,感兴趣的朋侪能够增加「马蜂窝手艺」民众号延续关注。

资本毛病

起首我们要明白下资本毛病捕捉的应用场景,更多的是感知 DNS 挟制 及 CDN 节点异常等,详细体式格局以下:

window.addEventListener('error', function (e) {
    var target = e.target || e.srcElement;
    if (target instanceof HTMLScriptElement) {
        // 上报 【资本毛病】事宜
    }
}, true)

这里只做基础演示,现实环境中我们会体贴更多的 Element 毛病,如 css、img、woff 等,人人能够依据差别的场景自行增加。

*资本毛病的应用场景更多依靠其他几个维度,如:__地区、运营商等,后续的篇幅中我们会详细解说。

API

市面上主流的框架(如 Axios、jQuery.ajax 等)中,基础上一切的 API 要求都是基于xmlHttpRequest 或许 fetch,所以捕捉全局接口毛病的体式格局就是封装 xmlHttpRequest 或许 fetch。这里,我们的 SDK 依然应用到上文说起的 AOP 头脑,对 API 举行阻拦。

1. XmlHttpRequest

var xhr = window.XMLHttpRequest;
var _open = xhr.prototype.open;
var _send = xhr.prototype.send;
var attr = {};
var openReplacement = function (method, url) {
    // 能够存储method、url、时刻办理等信息
    attr.duration = new Date().getTime();
    _open.apply(this, arguments);
}
var sendReplacement = function () {
    methods.addEvent(this, 'readystatechange', function (attr) {
        // 能够存储response的status、盘算客户端现实相应时刻
        attr.status = this.status;
        attr.duration = new Date().getTime() - attr.duration;
        // 上报【API】事宜
    }.bind(this, , JSON.parse(JSON.stringify(attr))));
    _send.apply(this, arguments);
}
xmlhttp.prototype.open = openReplacement;
xmlhttp.prototype.send = sendReplacement;

2. Fetch

须要注重的是,API 阻拦肯定要对 SDK 自身上报的 API 设置好疏忽,不然将会致使轮回上报题目。

var _fetch = window.fetch;
window.fetch = function () {
    var attr = {
        method: arguments[1].method,
        url: arguments[0],
        duration: new Date().getTime()
    };
    return _fetch.apply(this, arguments).then(res => {
        attr.status = res.status;
        attr.duration = new Date().getTime() - attr.duration;
        // 上报【API】事宜
        return res;
    });
}

日记上报

为了监控前端应用是不是一般运转,一般会在前端网络毛病与机能等数据,最终将这些数据上报到服务端。由于日记上报并非应用的主要功用逻辑,优先级比较低,所以我们在确保日记数据上报更高效的同时,还应该斟酌怎样尽量地削减与其他症结操纵的资本争抢。

1. sendBeacon

navigator.sendBeacon() 要领主要用于满足统计和诊断代码的须要。这些代码一般会在卸载文档之前,尝试经由过程 HTTP 将少许数据异步传输到 Web 服务器。它处理了日记上报在 unload 时成功率很低的题目。我们在埋点时有许多对脱离页面时上报的需求,由于 SendBeacon 是异步的,不会影响当前页到下一个页面的跳转速率,能够更牢靠地保证事宜上报成功率,而且不影响路由切换。

window.navigator.sendBeacon('上报事宜的api', '数据参数')

2. img.src

当浏览器不支撑 navigator.sendBeacon 时,我们能够采纳模仿图片加载的体式格局发送日记上报事宜,且不会存在跨域题目。

var img = new Image();
img.src = API + '?' + '数据参数'

3. 关于 XmlHttpRequest

这里不引荐用 XmlHttpRequest。XHR 虽然支撑异步要求,直接发送数据到后端,然则会遭到跨域和同源的限定。而经由过程日记上报 API 跟营业是不在一个域下的,假如采纳这类情势须要设置 Access-Control-Allow-Origin:* 跨域,异常不方便,而且在 unload 状况下上报发作的丢包率最高。

总结来看,日记上报引荐采纳 sendBeacon -> img.src。在不影响用户路由切换和壅塞用户的状况下丢包率能够控制在 10%-30%,详细要看用户群体对应的环境。

小结

高效的前端数据网络关于搭建前端监控平台来讲异常症结。本文我们分享了马蜂窝在保证数据网络实时、正确、周全等方面的一些思绪和实践。须要提醒人人注重的是,文中涉及到的演示只做了中心代码的症结形貌,不具备临盆应用,我们在现实应用中须要做好兼容及容错。

本文也将作为马蜂窝前端监控平台系列文章的开篇,以后还将连续推出埋点情势、数据处置惩罚和剖析、报警以及监控平台在详细营业中的应用等内容,迎接人人延续关注。

本文作者:王峥,马蜂窝大数据平台前端手艺专家。

(马蜂窝手艺原创内容,转载务必说明出处保留文末二维码图片,感谢合营。)

关注马蜂窝手艺,找到更多你想要的内容

《让前端监控数据收集更高效》


推荐阅读
  • 单页面应用 VS 多页面应用的区别和适用场景
    本文主要介绍了单页面应用(SPA)和多页面应用(MPA)的区别和适用场景。单页面应用只有一个主页面,所有内容都包含在主页面中,页面切换快但需要做相关的调优;多页面应用有多个独立的页面,每个页面都要加载相关资源,页面切换慢但适用于对SEO要求较高的应用。文章还提到了两者在资源加载、过渡动画、路由模式和数据传递方面的差异。 ... [详细]
  • vue使用
    关键词: ... [详细]
  • 本文总结了在编写JS代码时,不同浏览器间的兼容性差异,并提供了相应的解决方法。其中包括阻止默认事件的代码示例和猎取兄弟节点的函数。这些方法可以帮助开发者在不同浏览器上实现一致的功能。 ... [详细]
  • 本文介绍了闭包的定义和运转机制,重点解释了闭包如何能够接触外部函数的作用域中的变量。通过词法作用域的查找规则,闭包可以访问外部函数的作用域。同时还提到了闭包的作用和影响。 ... [详细]
  • IjustinheritedsomewebpageswhichusesMooTools.IneverusedMooTools.NowIneedtoaddsomef ... [详细]
  • JavaScript和HTML之间的交互是经由过程事宜完成的。事宜:文档或浏览器窗口中发作的一些特定的交互霎时。能够运用侦听器(或处置惩罚递次来预订事宜),以便事宜发作时实行相应的 ... [详细]
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • PHP图片截取方法及应用实例
    本文介绍了使用PHP动态切割JPEG图片的方法,并提供了应用实例,包括截取视频图、提取文章内容中的图片地址、裁切图片等问题。详细介绍了相关的PHP函数和参数的使用,以及图片切割的具体步骤。同时,还提供了一些注意事项和优化建议。通过本文的学习,读者可以掌握PHP图片截取的技巧,实现自己的需求。 ... [详细]
  • Voicewo在线语音识别转换jQuery插件的特点和示例
    本文介绍了一款名为Voicewo的在线语音识别转换jQuery插件,该插件具有快速、架构、风格、扩展和兼容等特点,适合在互联网应用中使用。同时还提供了一个快速示例供开发人员参考。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 不同优化算法的比较分析及实验验证
    本文介绍了神经网络优化中常用的优化方法,包括学习率调整和梯度估计修正,并通过实验验证了不同优化算法的效果。实验结果表明,Adam算法在综合考虑学习率调整和梯度估计修正方面表现较好。该研究对于优化神经网络的训练过程具有指导意义。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • 用Vue实现的Demo商品管理效果图及实现代码
    本文介绍了一个使用Vue实现的Demo商品管理的效果图及实现代码。 ... [详细]
  • 本文介绍了利用ARMA模型对平稳非白噪声序列进行建模的步骤及代码实现。首先对观察值序列进行样本自相关系数和样本偏自相关系数的计算,然后根据这些系数的性质选择适当的ARMA模型进行拟合,并估计模型中的位置参数。接着进行模型的有效性检验,如果不通过则重新选择模型再拟合,如果通过则进行模型优化。最后利用拟合模型预测序列的未来走势。文章还介绍了绘制时序图、平稳性检验、白噪声检验、确定ARMA阶数和预测未来走势的代码实现。 ... [详细]
  • 一、路由首先需要配置路由,就是点击good组件进入goodDetail组件配置路由如下{path:goodDetail,component:goodDetail}同时在good组件中写入如下点击事件,路由中加入 ... [详细]
author-avatar
凡秘能
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有