您好,如果喜欢我的文章,可以关注我的公众号「量子前端」,将不定期关注推送前端好文~
前端埋点实践
- 介绍
- 1. 实现自定义hook,监测组件
- 2. 收集数据
- 3.前端错误捕捉
- 4. 发送后端保存数据
- 5.收集数据展示
- 总结
介绍
这段时间博主一直在投入组件库的开发工作,最初其实就是想提供一套组件库来使用并且开源,和大家一起学习,最近突然有一个思路,可以从组件库文档页拉取一下用户的数据,来对组件库更好的维护。
组件库的链接在这里
主要思路还是采用的代码埋点,在每个组件的页面挂载的时候注入埋点,进行数据收集、最后提交给后端来进行长保存。
1. 实现自定义hook,监测组件
代码如下:
import { useEffect, useRef } from 'react';
import getUserIp from '../track/getUserIp';
import getNativeBrowserInfo from '../track/getNativeBrowserInfo';
import sendData from '../track/sendData';const usePageListener = (componentName: string) => {//监测单组件文档页面停留时间,进行埋点const leaveTime = useRef<number>(0);const timer = useRef<any>();useEffect(() => {//计算页面停留时间timer.current = setInterval(() => {leaveTime.current = leaveTime.current + 1;}, 1000);return () => {clearInterval(timer.current);};}, [leaveTime]);useEffect((): any => {return async () => {//组件销毁,如果停留时间大于十秒,发送单组件埋点记录console.log('销毁', componentName, leaveTime.current);let trackInfo = {componentName,leaveTime: leaveTime.current,};const userDeviceInfo = (await getUserIp()) as object; //用户个人相关信息const nativeBrowserInfo = (await getNativeBrowserInfo()) as object; //浏览器原生的信息trackInfo = { ...trackInfo, ...userDeviceInfo, ...nativeBrowserInfo };//将收集到的数据发送给后端const result = await sendData(trackInfo);return result;};}, []);
};export default usePageListener;
usePageListener hook主要有两个阶段:
- 组件挂载阶段,进行页面时间监听,计时用户在该页面停留了多少秒。
- 组件销毁阶段,停止计时,并开始收集数据,最后发送给后端。
2. 收集数据
我这里主要收集了两类数据,个人相关信息的收集函数getUserIp如下:
const getUserIp = () => {return new Promise((resolve, reject) => {const scriptElement = document.createElement('script');scriptElement.src = `http://pv.sohu.com/cityjson?ie=utf-8`;document.body.appendChild(scriptElement);scriptElement.onload = () => {try {document.body.removeChild(scriptElement);resolve(returnCitySN);} catch (e) {reject(e);}};});
};export default getUserIp;
这里是借助了搜狐的第三方接口来获取用户的IP地址和所在城市。
浏览器原生的数据方法getNativeBrowserInfo如下:
import { getNowTime } from '../getNowTime';type nativeBrowserInfoType = {domain?: string;url?: string;title?: string;referrer?: string;screenHeight?: number | string;screenWidth?: number | string;color?: number;lang?: string;ua?: string;watchTime?: string;memory?: string;connectTime?: string;responseTime?: string;renderTime?: string;
};
const formatMemory = (val: number) => {//格式化内存数据return Math.floor(val / 1024 / 1024) + 'mb';
};
const formatTimeToSecord = (val: number) => {//转换为秒return val / 1000 + 's';
};
const getNativeBrowserInfo = () => {//获取浏览器原生数据return new Promise((resolve) => {const params: nativeBrowserInfoType = {};if (document) {params.domain = document.domain || ''; //获取域名// params.url = String(document.URL) || ''; //当前Url地址params.title = document.title || '';// params.referrer = String(document.referrer) || ''; //上一跳路径}//Window对象数据if (window && window.screen) {params.screenHeight = window.screen.height || 0; //获取显示屏信息params.screenWidth = window.screen.width || 0;params.color = window.screen.colorDepth || 0;}//navigator对象数据if (navigator) {params.lang = navigator.language || ''; //获取所用语言种类params.ua = navigator.userAgent.toLowerCase(); //运行环境}//获取性能相关参数if (window && window.performance) {params.memory = formatMemory(window.performance.memory.usedJSHeapSize);params.connectTime = formatTimeToSecord(window.performance.timing.connectEnd - window.performance.timing.connectStart,);params.responseTime = formatTimeToSecord(window.performance.timing.responseEnd - window.performance.timing.responseStart,);params.renderTime = formatTimeToSecord(window.performance.timing.domComplete - window.performance.timing.domLoading,);}params.watchTime = getNowTime();resolve(params);});
};export default getNativeBrowserInfo;
这里是收集了设备、运行环境以及页面加载内存性能相关的数据,也是可以知道h5在每个设备中是否有不一样的加载表现,从而进行针对性优化。
最终收集到的数据样例是这样的:
3.前端错误捕捉
通过window.onerror方法,捕捉到前端出现的错误信息,并上报给后端,主要是实现代码如下:
import { getNowTime } from '../getNowTime';type errorList<T> = {errorMessage?: T;scriptURI?: T;errorObj?: T;happenURI?: T;happenTime?: T;
};
const getErrorInfo = () => {const errorList: errorList<string | Event | number | undefined> = {};window.onerror = (errorMessage, scriptURI, errorObj) => {errorList.errorMessage = errorMessage;errorList.scriptURI = scriptURI;errorList.happenURI = window.location.href.replace('#', '');errorList.errorObj = errorObj;errorList.happenTime = getNowTime();const sendScript = document.createElement('script');const requestAddress = `http://react-view-ui.com:9999/saveErrorMessage?info=${JSON.stringify(errorList,)}`;sendScript.src = requestAddress;document.body.appendChild(sendScript);};
};export { getErrorInfo };
这里主要收集了报错信息、报错的页面地址、报错时间等参数,这里我们就可以自己去mock出错误。
4. 发送后端保存数据
数据收集完毕,准备发送给后端,这里是加入了一个script脚本,请求后端,并把收集到的数据传给后端,代码如下:
const sendData = (params: object) => {const sendScript = document.createElement('script');const requestAddress =process.env.NODE_ENV === 'development'? `http://localhost:9999/saveComponentLog?info=${JSON.stringify(params)}`: `http://react-view-ui.com:9999/saveComponentLog?info=${JSON.stringify(params)}`;sendScript.src = requestAddress;sendScript.async = true;document.body.appendChild(sendScript);return new Promise((resolve, reject) => {sendScript.onload = () => {try {document.body.removeChild(sendScript);resolve('');} catch (e) {reject(e);}};});
};
export default sendData;
至此…埋点就做完了,线上服务器也可以实时获取到用户的数据,保存在数据库中,提供给我进行参考了~哈哈哈
5.收集数据展示
这里一共有两张表,用户信息表和错误表。
用户信息表:
错误表:
总结
最后…留一下React-View-UI的链接~~
Concis组件库线上链接:http://react-view-ui.com:92
github:https://github.com/fengxinhhh/Concis
npm:https://www.npmjs.com/package/concis
开源不易,欢迎学习和体验,喜欢请多多支持,有问题请留言。