各位观众老爷,大家好!今天咱们聊聊UniApp项目的性能监控,保证你的代码跑得飞起,用户体验蹭蹭上涨!
咱们的目标是:打造一个能同时监控App、H5和小程序三端的性能监控系统。听起来有点唬人,但别怕,一步一步来,你会发现其实也没那么难。
一、战略规划:监控啥?怎么监控?
在开始动手之前,我们需要明确两个问题:
-
监控哪些指标?
- 加载时间: 首屏加载时间、资源加载时间(JS、CSS、图片等)。
- 页面渲染时间: 页面DOM渲染时间。
- 接口请求时间: API请求耗时、成功率。
- JS错误: JS错误、Promise rejection。
- 资源错误: 图片、CSS等资源加载失败。
- 内存占用: App端内存占用情况。
- CPU占用: App端CPU占用情况。
- 用户行为: 页面PV、UV、点击事件等。
- 白屏时间: 用户看到第一个像素点的时间。
- 首次可交互时间 (TTI): 用户可以开始交互的时间。
这些指标就像是你身体的各项体检指标,哪个不正常了,你就得赶紧看看是不是哪里出了问题。
-
怎么监控?
- 埋点: 在关键代码处插入监控代码,记录性能数据。
- API Hook: 拦截关键API,例如
uni.request
,记录请求信息。 - 错误捕获: 监听全局错误事件,例如
window.onerror
和unhandledrejection
。 - Performance API: 利用浏览器提供的Performance API,获取更详细的性能数据。
二、战术实施:代码实现
咱们分模块来,先打好地基,再盖高楼。
-
基础模块:数据收集
首先,我们需要一个统一的数据收集模块,负责收集各种性能数据,并将其发送到服务器。
// utils/monitor.js const API_URL = '你的监控服务器地址'; // 替换成你的服务器地址 function sendData(data) { uni.request({ url: API_URL, method: 'POST', data: data, header: { 'Content-Type': 'application/json' } }); } export default { log(type, data) { const reportData = { type: type, data: data, timestamp: Date.now(), platform: uni.getSystemInfoSync().platform, // 平台信息,方便区分App、H5和小程序 appId: uni.getSystemInfoSync().appId || 'H5', //如果是H5则返回H5 }; sendData(reportData); }, // 记录错误信息 error(error) { this.log('error', { message: error.message, stack: error.stack, }); }, // 记录性能数据 performance(name, value) { this.log('performance', { name: name, value: value, }); }, };
这个
monitor.js
模块提供了三个主要方法:log(type, data)
:用于记录各种类型的数据,例如错误、性能数据等。error(error)
:专门用于记录错误信息。performance(name, value)
:用于记录性能数据。
这样,我们就有了一个统一的数据收集入口,所有需要上报的数据都通过这个模块发送到服务器。
-
App端监控
App端可以利用
uni.getSystemInfoSync
获取更详细的设备信息,还可以利用uni.onAppEnterForeground
和uni.onAppEnterBackground
监听App的前后台切换,记录App的活跃情况。// App.vue import monitor from './utils/monitor'; export default { onLaunch: function() { console.log('App Launch'); // 监听全局错误 uni.onError(function(error) { monitor.error(error); }); // 监听Promise rejection uni.onUnhandledRejection(function(error) { monitor.error(error); }); }, onShow: function() { console.log('App Show'); }, onHide: function() { console.log('App Hide'); }, };
-
H5端监控
H5端可以利用
window.onerror
和unhandledrejection
监听全局错误,利用Performance API
获取更详细的性能数据。// 在main.js或者其他入口文件中 import monitor from './utils/monitor'; // 监听全局错误 window.onerror = function(message, source, lineno, colno, error) { monitor.error(error); }; // 监听Promise rejection window.addEventListener('unhandledrejection', function(event) { monitor.error(event.reason); }); // 监听白屏时间 function getFirstPaintTime() { if (window.performance) { const timing = window.performance.timing; const firstPaintTime = timing.domContentLoadedEventStart - timing.navigationStart; monitor.performance('firstPaintTime', firstPaintTime); } } //在页面加载完成后获取 window.onload = getFirstPaintTime; //监听首次可交互时间(TTI) function getTTI() { if ('PerformanceObserver' in window) { const observer = new PerformanceObserver((list) => { list.getEntries().forEach((entry) => { if (entry.name === 'dom-interactive') { monitor.performance('tti', entry.startTime); observer.disconnect(); } }); }); observer.observe({ type: 'navigation', buffered: true }); } } document.addEventListener('DOMContentLoaded', getTTI);
H5端还可以通过
addEventListener
监听load
事件,记录页面加载完成的时间。 -
小程序端监控
小程序端与App端类似,可以使用
uni.onError
和uni.onUnhandledRejection
监听全局错误,使用uni.getSystemInfoSync
获取设备信息。// app.js import monitor from './utils/monitor'; App({ onLaunch: function() { // 监听全局错误 uni.onError(function(error) { monitor.error(error); }); // 监听Promise rejection uni.onUnhandledRejection(function(error) { monitor.error(error); }); }, });
-
接口请求监控
我们可以通过
uni.request
的success
和fail
回调函数,记录接口请求的耗时和状态。// utils/request.js import monitor from './utils/monitor'; const originalRequest = uni.request; uni.request = function(options) { const startTime = Date.now(); return originalRequest({ ...options, success: function(res) { const endTime = Date.now(); const duration = endTime - startTime; monitor.performance('api_request', { url: options.url, duration: duration, statusCode: res.statusCode, }); if (options.success) { options.success(res); } }, fail: function(err) { const endTime = Date.now(); const duration = endTime - startTime; monitor.error({ message: `API request failed: ${options.url}`, error: err, duration: duration, }); if (options.fail) { options.fail(err); } }, }); }; export default uni.request;
这段代码通过
Hook
了uni.request
方法,在每次请求前后记录时间戳,计算请求耗时,并将数据发送到服务器。 -
用户行为监控
用户行为监控可以记录用户的点击事件、页面跳转等行为,帮助我们了解用户的使用习惯。
// 在需要监控的页面中 import monitor from '../../utils/monitor'; export default { methods: { onClickButton() { // 记录点击事件 monitor.log('click', { element: 'button', text: '点击按钮', }); // 其他逻辑 }, onPageShow(){ // 记录页面进入事件 monitor.log('pageShow', { pageName: '当前页面名称', }); } }, onShow(){ this.onPageShow() } };
三、服务器端:数据存储与分析
光收集数据还不够,我们需要一个服务器来接收、存储和分析这些数据。
-
数据接收
服务器需要提供一个API接口,用于接收客户端发送的性能数据。
// Node.js (Express) 示例 const express = require('express'); const bodyParser = require('body-parser'); const app = express(); const port = 3000; app.use(bodyParser.json()); app.post('/api/monitor', (req, res) => { const data = req.body; console.log('Received monitor data:', data); // TODO: 将数据存储到数据库 res.sendStatus(200); }); app.listen(port, () => { console.log(`Server listening at http://localhost:${port}`); });
这个简单的Node.js服务器接收客户端发送的JSON数据,并将其打印到控制台。你需要根据自己的实际情况,将数据存储到数据库中。
-
数据存储
常用的数据库包括:
- MySQL: 关系型数据库,适合存储结构化数据。
- MongoDB: NoSQL数据库,适合存储半结构化数据,例如JSON格式的性能数据。
- Elasticsearch: 搜索引擎,适合存储和分析大量的日志数据。
选择哪种数据库取决于你的数据量、数据结构和分析需求。
-
数据分析
有了数据,就可以进行各种分析了,例如:
- 统计报表: 统计各种性能指标的平均值、最大值、最小值等。
- 趋势分析: 分析性能指标随时间的变化趋势。
- 异常告警: 当性能指标超过阈值时,发送告警通知。
- 用户行为分析: 分析用户的使用习惯,优化产品设计。
可以使用各种数据分析工具,例如:
- Grafana: 数据可视化工具,可以将数据以图表的形式展示出来。
- Kibana: Elasticsearch的可视化工具,可以用于分析日志数据。
- 自定义脚本: 使用Python、R等脚本语言,编写自定义的分析逻辑。
四、优化建议
- 数据采样: 如果数据量太大,可以采用数据采样的方式,只收集部分数据。
- 数据压缩: 压缩数据可以减少网络传输的开销。
- 异步发送: 异步发送数据可以避免阻塞主线程。
- 错误上报: 错误上报需要包含足够的信息,例如错误信息、堆栈信息、设备信息等。
- 性能监控: 性能监控本身也会消耗一定的性能,需要权衡监控的粒度和性能开销。
五、总结
咱们今天讲了UniApp性能监控系统的设计思路和实现方法,包括数据收集、App端监控、H5端监控、小程序端监控、接口请求监控、用户行为监控、服务器端数据存储与分析等方面。
记住,性能监控是一个持续的过程,需要不断地优化和改进。希望今天的分享对你有所帮助,祝你的UniApp项目性能越来越好!