前端篇系列长文:
轻轻喷,借鉴了很多文章,刚学完理出框架只完成了一点点,做一个复习,还在更新大改中,能帮到大家就最开心了,喜欢可以点个赞,持续更新中,谢谢大家,祝大家鹏程万展
- 高级前端篇-监控平台(juejin.cn/post/748261...)
- 高级前端篇-自动化测试(juejin.cn/post/748258...)
- 高级前端篇-脚手架开发(juejin.cn/post/748073...)
- 高级前端篇-前端工程化(juejin.cn/post/748052...)
- 高级前端篇-性能优化篇(juejin.cn/post/748112...)
一、背景与基础概念
在当今数字化时代,前端应用的复杂性和用户交互的多样性不断增加。前端埋点和监控技术应运而生,成为了开发者和产品运营人员的得力助手。通过收集用户在 Web 应用或移动应用中的行为数据,我们能够深入分析用户的行为习惯,实时掌握应用的性能状况,及时发现并解决问题,有效处理系统故障。这些数据不仅为产品优化提供了关键依据,还助力制定更精准的营销策略,最终提升用户体验和产品价值。
埋点:洞悉用户行为的窗口
埋点作为一种重要的数据采集技术,主要用于收集用户在应用中的行为数据。其实现方式是在代码中巧妙插入特定的监控代码,即 "埋点代码"。当用户触发特定事件,比如点击按钮、浏览页面、滑动屏幕等,埋点代码便会捕获相关信息,并将这些信息发送到数据分析平台进行存储和深入分析。通过埋点收集到的数据,开发者、产品经理和运营团队能够清晰了解用户在使用应用过程中的操作习惯和需求,为产品优化、营销策略制定和用户体验改进提供坚实的数据支撑。
国内流行的埋点工具
- TalkingData:这是一个功能强大的移动数据分析平台,提供了丰富的功能,如用户画像构建、详细的行为分析、精准的漏斗分析等。通过对用户行为数据的深入挖掘,帮助企业更好地了解用户,优化产品功能和运营策略。
- 腾讯移动分析(MTA) :腾讯推出的这款移动应用分析工具,专注于用户行为分析、事件追踪以及渠道效果分析。它能够帮助开发者准确把握用户在应用内的行为路径,评估不同渠道的推广效果,从而针对性地进行优化。
- 阿里云 ARMS:作为阿里云提供的应用性能监控服务,ARMS 具备性能埋点、错误监控以及资源优化等功能。它不仅能帮助企业监控应用的性能指标,还能及时发现并解决应用中出现的错误,提升应用的稳定性和用户体验。
- 腾讯云 TA(腾讯分析) :该数据分析工具同样提供了用户行为分析、事件追踪和渠道效果分析等功能,助力企业深入了解用户行为,优化产品和运营策略。
- 诸葛 IO:这是一个专业的用户行为分析平台,提供了事件追踪、漏斗分析、留存分析等功能。通过对用户行为数据的多维度分析,帮助企业找到产品优化的关键点,提高用户留存率和活跃度。
监控:保障应用性能的卫士
监控的核心作用是实时收集应用的性能表现数据,如页面加载速度、响应时间、资源加载情况等。这些数据为性能优化提供了明确的方向,帮助开发者迅速找到性能瓶颈并进行针对性优化。同时,监控还能及时发现应用中的错误和异常,通过对监控数据的深入分析,开发者能够快速定位问题原因,采取有效措施解决问题,最大程度降低故障对用户体验的影响。
流行的监控工具
- Sentry:作为一个开源的前端错误监控工具,Sentry 能够精准捕获和报告 JavaScript 及前端框架的错误和异常。它提供详细的错误信息和堆栈跟踪,极大地帮助开发人员快速定位和解决问题,提高开发效率。
- Google Analytics(谷歌分析) :这是一款全球广泛使用的网站统计和分析工具,具备丰富的功能,包括用户行为分析、性能监控、事件追踪等。通过对网站数据的全面分析,帮助企业了解用户行为,优化网站性能和用户体验。
- Lighthouse:由 Google 提供的开源网站性能分析工具,Lighthouse 可以对页面的性能、可访问性、SEO 等方面进行全面评估。它提供详细的报告和优化建议,帮助开发者提升网站的整体质量。
- WebPageTest:这是一个在线的网站性能测试工具,能够测试页面加载速度、首屏渲染时间等关键性能指标。通过对不同地区、不同网络环境下的测试,帮助企业了解用户在各种情况下的体验,优化网站性能。
二、行业通用方案剖析
随着前端技术的飞速发展,前端监控已成为众多项目不可或缺的一部分。在实际项目中,我们常常会采用各种开源项目或付费平台来实现前端监控,如sentry
、阿里的ARMS
,甚至小程序自带的前端监控服务。
(1)sentry
sentry
主要专注于收集错误信息,支持大多数流行语言的客户端和服务端。然而,它对小程序的支持存在不足,虽然目前有大公司根据sentry
的上报数据结构,自行实现了小程序SDK
并开源,但该SDK
的关注度和流行度相对较低。此外,除了错误收集,它在其他类型的前端监控能力方面相对较弱。
(2)阿里 ARMS
ARMS
提供的功能较为齐全,对多种客户端都有良好的支持,包括小程序。它涵盖了性能监控、错误追踪、用户行为分析等多个方面,功能全面且符合国内的业务环境。不过,使用ARMS
需要支付一定的费用。
(3)小程序自带监控
微信小程序不断完善内部监控功能,其涵盖的监控范围逐渐丰富,包括性能监控、错误监控等。但小程序自带监控的局限性在于,它仅能支持小程序本身,无法对其他类型的前端应用进行监控。
尽管这些开源或平台前端监控服务为我们提供了便利,但在实际使用过程中,它们也暴露出一些不足之处。例如,不同的监控工具和平台导致系统分散,难以统一管理;在满足自定义数据收集和查询需求方面存在困难;部分工具的特性更新缓慢,BUG
解决周期较长;而且进行二次开发时,往往面临较大的难度。
三、系统架构与融合
3.1 基本构成
一个完整的前端监控系统通常由多个关键部分组成,各部分相互协作,共同实现前端监控的功能。
-
客户端 SDK:
- web:用于收集 Web 应用中的用户行为和性能数据,如页面加载时间、用户点击事件等。
- 小程序:针对小程序的特点,收集小程序运行过程中的数据,包括页面加载性能、接口调用情况等。
- ios:专门为 iOS 应用开发的 SDK,能够收集 iOS 应用中的各种数据,如应用启动时间、页面切换时间等。
- android:适用于 Android 应用,用于收集 Android 应用中的用户行为和性能数据。
-
服务端 node + EggJs :使用
node
作为服务端开发语言,node
具有出色的I/O
性能,非常适合I/O
密集型场景,且与前端技术栈相契合。EggJs
是一个基于node
的框架,它简单易用,文档完善,大部分熟悉node
的前端程序员能够快速上手。服务端负责接收客户端SDK
上报的数据,并进行处理和存储。 -
数据库 Redis + Mongo + mongooseJs (orm) :
- Mongo :作为持久化存储数据库,Mongo 是文档模型数据库,其数据结构类似
json
,方便与node
配合使用。这种数据结构天生适合日志系统,能够方便地存储和扩展监控数据。 - Redis :用作数据缓存,Redis 是简单易用的高性能
key - value
数据库,在市场上占据主流地位,被广泛熟知。它能够快速缓存常用数据,提高系统的响应速度。
- Mongo :作为持久化存储数据库,Mongo 是文档模型数据库,其数据结构类似
-
管理台 Vue + ElementUI :管理台用于数据查询与管理,使用
Vue
框架结合ElementUI
组件库进行开发,能够快速搭建出简洁美观、功能强大的管理界面,方便用户对监控数据进行查看和管理。
为了实现前端监控,首先要解决的是客户端数据收集问题。为此,我们开发封装了一个统一的SDK
,方便客户端集成监控系统。在项目初期,我们优先支持web
和微信小程序客户端,随着系统的不断迭代,现在也已支持native
客户端。SDK
收集到数据后,通过服务端接口上报。服务端接收到数据后,先将数据存储在redis
中,然后根据自身的消费能力,从redis
中拉取数据进行处理分析,最后将处理后的数据存储到mongo
中。用户可以通过管理后台查看处理好的应用数据。
3.2 系统融合与关联
为了丰富前端监控系统的功能,提高其易用性,减少工作量,我们将公司内部现有的优质系统进行了接入和融合。
- SSO 系统 :企业内部的
SSO
单点登录系统为每个员工注册了一个账户,员工可以通过账户密码、企业微信扫码或微信扫码等方式登录。接入SSO
系统,不仅解决了不同系统之间的账户密码和登录方式不一致的问题,还方便了系统之间的相互跳转和接口请求,提高了用户的使用体验。 - 加入内部导航黄页:将前端监控系统的项目加入内部导航页,方便员工快速访问,提高系统的使用便捷性。
- 本地日志系统 finder elasticsearch :前端监控系统的
node
后端服务会产生本地日志,通过将日志存储到约定目录,运维服务会收集这些日志,并提供finder
和elasticsearch
两个查询系统。finder
按照时间和文件夹结构划分日志,查看视角类似于直接在服务器上查看本地日志,大多数情况下,用户更习惯使用finder
进行日志查看。而elasticsearch
则更适合通过搜索方式查询日志,方便用户快速定位所需信息。 - APM 系统 skywalking :
APM
(应用性能管理)的目标是通过各种探针采集数据,收集关键指标,并搭配数据呈现,实现对应用程序性能管理和故障管理的系统化解决方案。我们企业内部统一使用skywalking
,由于大部分服务是java
开发,skywalking
提供了node
探针,使我们的前端监控系统后端node
服务也能够接入。接入后,我们可以通过skywalking
管理台查询后端node
服务的性能以及调用情况。在这个过程中,traceId
起着关键作用。APM
工具会在服务端生成traceId
,它标示一次调用的上下文id
,通过此id
可以查询所做事情的足迹链。后端服务可以通过前端http
请求把这次调用的traceId
通过响应头返回给客户端。前端监控的前端SDK
探针便可以收集traceId
,从而打通前端监控与后端监控。在前端监控管理后台,我们不仅能看到前端的监控网络日志,还能通过traceId
查询到后端链路信息。 - 告警平台:前端监控系统需要实时或定时推送一些告警邮件等信息。内部告警平台提供了告警策略配置功能,并会主动拉取前端监控数据。接入告警平台,能够减轻前端监控系统自身在告警方面的工作量,确保告警信息能够及时、准确地发送给相关人员。
- 操作日志平台:在网关层,操作日志平台可以拦截管理台的操作请求,记录用户在系统中的操作行为。这些操作日志有助于进行敏感操作追溯以及报警,保障系统的安全和合规性。
- SPA 平台 :
SPA
平台是公司内部自研的静态资源发布平台,可用于半自动化管理业务项目,包括配置注入、静态资源管理等。前端监控在收集到压缩代码的报错时,需要通过sourceMap
文件解析转换为源代码。大部分前端监控方案需要手动上传sourceMap
文件到监控系统,而使用SPA
平台后,资源被统一管理,我们可以通过内部配置将sourceMap
文件存放在约定位置,免去了业务方手动上传的繁琐操作,提高了系统的易用性。
3.3 高效运维
一个稳定运行的线上系统离不开高效的运维服务。
- 日志抓取 :运维服务负责抓取前端监控系统产生的各种日志,包括客户端
SDK
上报的日志、服务端运行日志等,这些日志为系统的问题排查和优化提供了重要依据。 - 自动化构建:通过自动化构建工具,实现代码的自动编译、打包和部署,提高开发和部署效率,减少人为错误。
- 容器化:将前端监控系统进行容器化部署,使用容器技术(如 Docker)可以实现环境的一致性和隔离性,方便系统的管理和维护,提高系统的可扩展性和稳定性。
- 负载均衡:采用负载均衡技术,将客户端请求均匀分配到多个服务器实例上,避免单个服务器负载过高,提高系统的整体性能和可用性。
- 健康检测、安全关闭:前端监控系统随时都会接收业务方上报的数据,在系统重启或关闭时,必须确保服务不间断且数据不丢失。当更新代码并重新构建时,首先会预先启动新的容器,待新容器启动完成后,逐步关闭替换旧的服务。旧服务在关闭前会收到通知,停止接收新的处理任务,待所有正在执行的任务处理完毕后再关闭,从而保障系统的稳定运行。
四、数据收集与分析
4.1 数据收集
数据收集是前端监控系统的核心环节之一,主要收集以下几类数据:
-
性能 :收集
Native
热冷启动、Web
页面加载、静态资源、ajax
接口等性能信息。相关指标包括加载时间、http
协议版本、响应体大小等。这些数据为业务整体质量提升提供数据支撑,有助于解决慢查询等问题,优化用户体验。 -
错误 :收集
Native
和js
报错、静态资源加载错误、ajax
接口加载错误等常规错误。重点说明一下 "业务接口错误 (bussiness)":客户端发送ajax
请求后端业务接口,接口返回的json
数据结构中一般会有errorcode
和message
两个字段,errorcode
为业务接口内部定义的状态码。通常约定正常业务响应时errorcode==0
,若errorcode
不为0
,则可能表示出现了异常问题或可预见的异常情况,这类错误数据需要被收集。由于不同团队或接口的约定可能不同,我们提供一个预设方法,该方法在ajax
请求响应后调用,业务方根据自身约定和响应的json
数据,在预设方法中编写判断逻辑来控制是否上报。例如:
javascript
javascript
errcodeReport(res) {
if (Object.prototype.toString.call(res) === '[object Object]' && res.hasOwnProperty('errcode') && res.errcode!== 0) {
return { isReport: true, errMsg: res.errmsg,code: res.errcode };
}
return { isReport: false };
}
- 辅助信息 :除了性能和错误数据,还需要收集很多其他信息,如用户的访问轨迹、用户点击行为、用户 ID、设备版本、设备型号、UV/UA 标识、
traceId
等。这些辅助信息在排查问题时非常重要,有时我们需要将前端监控数据与其他系统数据关联起来,才能全面地解决问题。
4.2 数据录入
数据收集后,不能直接录入数据库,需要经过一定处理。
- SDK 过滤 :一些三方业务接口和资源请求量较大,且自身可能频繁报错,或者存在一些内部接口我们不希望收集数据,这些数据会干扰监控数据的准确性。因此,客户端
SDK
提供过滤配置,业务方可以根据业务需求过滤不需要收集的接口等,也可以内置企业约定过滤的接口路径。 - 服务端处理 :
SDK
上报的数据,服务端需要进行二次处理后再保存。例如,为了方便查询,可能需要对原始数据进行拆分等操作,确保存储到数据库中的数据格式和结构符合查询和分析的要求。
4.3 数据分析
数据录入数据库后,就可以进行分析和查询了。除了管理台提供的基础数据查询功能,我们还通过图表和日报等形式来满足不同的使用场景。
- 日报:日报从已有的数据中筛选出重点信息和分析后的内容。虽然监控平台随时可查,但用户可能无法时刻关注。日报主要面向开发和测试人员,帮助他们及时了解系统的关键信息和问题。
- 图表:图表是一种直观的数据展示形式,如页面性能加载实时图表、实时错误图表等。在上线新版本等关键时期,开发人员可以通过实时关注图表变化,及时发现性能问题和错误趋势,为及时调整和优化提供依据。
五、问题发现与解决
5.1 自动化集成测试
JS - SDK
作为一个需要长期维护和更新的独立库,被广泛应用于众多业务项目中。随着代码量和特性的不断增加,人工测试成本急剧上升,测试覆盖率低,开发过程缺乏安全感。因此,我们从零开始完善自动化集成测试。JS - SDK
主要通过加入探针监听业务项目的运行状态来收集信息,集成测试是重点关注对象。由于Web SDK
运行依赖Web
浏览器环境,不能单纯在node
中运行,目前我们采用两种测试方式:
- 终端测试:支持持续集成环境,即代码提交到仓库后,在托管平台提供的环境中进行托管测试,确保代码在不同环境中的兼容性和稳定性。
- 浏览器测试 :让代码运行在真实的浏览器环境中,不仅可以进行功能测试,还能进行浏览器兼容性测试,确保
SDK
在各种主流浏览器上都能正常工作。
5.2 数据聚合
在管理台查看监控数据时,需要对数据进行聚合归类,以便清晰展示。但实际中存在一些影响数据聚合的因素:
- 动态路由 :部分接口使用动态路由设置参数,如
xxx.com/api/getuid/15501/detail
。这种接口会导致无法根据url
聚合同一个接口。为此,SDK
默认将此类接口的动态参数部分替换为*
,例如上述链接变为xxx.com/api/getuid/*/detail
,这样服务端就能将它们归类为一个接口。目前采用正则匹配全数字的方式,适用于内部接口服务参数为纯数字的情况。若动态参数部分存在非纯数字参数,则无法判别,此时需要SDK
提供配置列表,由业务方配置相关链接,
六、专有名词解释
- PV(Page View) :页面浏览量,指用户访问网站页面的次数。每一次页面刷新或重新加载都会使 PV 增加。它反映了页面的受欢迎程度和用户对内容的关注度。例如,一个新闻网站某篇热门文章一天内 PV 达到 10 万,说明该文章被大量用户浏览。
- UV(Unique Visitor) :独立访客数,指在一定时间内访问网站的不同用户数量。同一用户在一天内多次访问只计为 1 个 UV。通过 UV 可了解网站的实际用户覆盖范围。比如,一个电商网站一天的 UV 为 5 万,意味着当天有 5 万不同用户访问了该网站。
- TTFB(Time to First Byte) :首字节时间,是指从浏览器发起请求到接收到服务器返回的第一个字节所花费的时间。它反映了服务器的响应速度,受网络延迟、服务器性能等因素影响。例如,一个页面的 TTFB 为 500ms,说明从用户请求到开始接收数据用了 0.5 秒。
- FCP(First Contentful Paint) :首次内容绘制时间,指浏览器首次将任何文本、图像、非空白 canvas 或 SVG 渲染到屏幕的时间。这是衡量页面加载速度和用户体验的重要指标。如果 FCP 在 1 秒内,用户通常会感觉页面加载迅速。
七、前端性能监控
-
页面加载性能
- 使用 Performance API:浏览器提供的 Performance API 可精确测量页面加载相关时间。例如,获取页面完全加载时间:
javascript
javascript
const loadTime = window.performance.timing.loadEventEnd - window.performance.timing.navigationStart;
console.log(`页面加载时间: ${loadTime} 毫秒`);
- 资源加载监控 :监听
load
事件,统计所有资源(如脚本、样式表、图片)的加载时间,找出加载缓慢的资源。
javascript
ini
const resources = [];
const resourceTypes = ['script','style', 'image'];
resourceTypes.forEach(type => {
document.addEventListener('load', function (event) {
if (event.target.tagName.toLowerCase() === type) {
const startTime = event.target.startTime;
const endTime = performance.now();
const loadTime = endTime - startTime;
resources.push({ type, loadTime });
}
});
});
-
用户交互性能
- 帧率监控 :通过
requestAnimationFrame
计算帧率,判断页面动画和交互的流畅度。正常帧率应保持在 60fps 左右。
- 帧率监控 :通过
javascript
ini
let frameCount = 0;
let startTime = performance.now();
function monitorFPS() {
requestAnimationFrame(() => {
frameCount++;
const now = performance.now();
const elapsed = now - startTime;
if (elapsed >= 1000) {
const fps = frameCount / (elapsed / 1000);
console.log(`当前帧率: ${fps} fps`);
frameCount = 0;
startTime = now;
}
monitorFPS();
});
}
monitorFPS();
- 输入延迟监控 :使用
Performance.now()
记录用户输入事件(如点击、按键)发生时间和实际处理时间,计算输入延迟。
八、前端错误收集
-
全局错误捕获
- window.onerror :在浏览器环境中,可通过
window.onerror
捕获未被 try - catch 块处理的 JavaScript 错误。
- window.onerror :在浏览器环境中,可通过
javascript
javascript
window.onerror = function (message, source, lineno, colno, error) {
console.log(`错误信息: ${message}`);
console.log(`错误源: ${source}`);
console.log(`行号: ${lineno}`);
console.log(`列号: ${colno}`);
console.log(`错误对象: ${error}`);
return true; // 阻止默认的错误处理行为
};
- Promise.reject:全局捕获未处理的 Promise 拒绝错误。
javascript
javascript
window.addEventListener('unhandledrejection', function (event) {
console.log(`未处理的Promise拒绝: ${event.reason}`);
event.preventDefault();
});
-
框架特定错误捕获
- React :使用
ErrorBoundary
组件捕获其子组件树中的 JavaScript 错误。
- React :使用
javascript
javascript
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
componentDidCatch(error, errorInfo) {
console.log(`React错误: ${error}`);
console.log(`错误信息: ${errorInfo}`);
this.setState({ hasError: true });
}
render() {
if (this.state.hasError) {
return <div>发生错误,组件渲染失败</div>;
}
return this.props.children;
}
}
- Vue :在 Vue 应用中,通过
errorHandler
全局配置捕获错误。
javascript
javascript
Vue.config.errorHandler = function (err, vm, info) {
console.log(`Vue错误: ${err}`);
console.log(`组件实例: ${vm}`);
console.log(`错误信息: ${info}`);
};
前端监控平台是保障前端应用质量的重要手段。通过了解主流监控平台方案、掌握性能监控与错误收集方法、熟悉关键专有名词,前端架构师能够构建更稳定、高效的前端应用,为用户带来优质体验。