前端埋点实现

2023-11-09

您好,如果喜欢我的文章,可以关注我的公众号「量子前端」,将不定期关注推送前端好文~

介绍

这段时间博主一直在投入组件库的开发工作,最初其实就是想提供一套组件库来使用并且开源,和大家一起学习,最近突然有一个思路,可以从组件库文档页拉取一下用户的数据,来对组件库更好的维护。

组件库的链接在这里

主要思路还是采用的代码埋点,在每个组件的页面挂载的时候注入埋点,进行数据收集、最后提交给后端来进行长保存。

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主要有两个阶段:

  1. 组件挂载阶段,进行页面时间监听,计时用户在该页面停留了多少秒。
  2. 组件销毁阶段,停止计时,并开始收集数据,最后发送给后端。

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

开源不易,欢迎学习和体验,喜欢请多多支持,有问题请留言。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

前端埋点实现 的相关文章

  • 亚马逊联属网络营销搜索广告脚本:未捕获类型错误:无法读取 null 属性“getBoundingClientRect”

    我在我的网站上嵌入了亚马逊联属原生搜索广告 当我在我的开发笔记本电脑上进行测试时 搜索广告 显示没有任何问题 但是 当部署到托管提供商时 遇到运行时错误并且亚马逊搜索广告未显示 请在这里帮忙 Error Uncaught TypeError
  • 有没有办法从 PhantomJS 的键盘读取用户输入?

    我使用 PhantomJS 登录网站 必须手动输入验证码 如何将验证码图像保存到磁盘 然后在 PhantomJS 控制台中手动输入验证码 我遇到了同样的问题 只需将系统模块与 page render 和一些传递给 page evaluate
  • 从 JavaScript 加载图像

    在我的专辑幻灯片放映页面上 我有类似的代码 span style display none img src imageUrl span span show loader span in showImage 我确定图像已加载 因此我显示图像并
  • Javascript“this”在 IE 中丢失上下文

    以下在 firefox safari chrome 中工作正常 在 IE 中 this 似乎在 handleEvent 函数中丢失上下文 警报的结果是 object Window 这不是我想要的 当从handleEvent 输出时 this
  • Mongoose 查询执行后回调函数从未被调用

    以下是我的代码 mongoose connect mongodb localhost mydatabase var db mongoose connection db on error console error bind console
  • 使用非常大的背景位置偏移是否存在性能问题?

    我正在构建一个进度条控件 并且正在研究它实际上并不显示进度 而只是旋转 正在发生某事 的指示器的情况 我的设计基本上是交替的对角条纹 本质上是一个像这样的理发杆 但是 旋转 由于希望将尽可能多的负载转移给渲染引擎 我想为此使用 CSS 过渡
  • 有没有办法让 jslint 在 javascript 的下一行中使用大括号?

    我改变了我的编码风格 function getParams entity use strict var accountID store getItem AccountID switch entity case Topic to functi
  • 每n秒执行一次函数

    我制作了这个在 10 秒后点击链接的代码片段 function timeout window setTimeout function img left click 1000 setTimeout timeout 1000 timeout 我
  • 为动态加载的 HTML 内容触发 Bootstrap JS 行为

    我正在动态加载包含 Bootstrap 标记的 HTML 模板 但是 Bootstrap Javascript 行为不会应用于加载的内容 例如 如果加载的内容包含 Bootstrap 模式的标记 则该模式将无法正确运行 有没有办法可以触发
  • tomcat 7.0.50 java websocket 实现给出 404 错误

    我正在尝试使用 Java Websocket API 1 0 JSR 356 中指定的带注释端点在 tomcat 7 0 50 上实现 websocket 以下是我如何对其进行编码的简要步骤 1 使用 ServerEndpoint注解编写w
  • jslint 配置 |传递全局变量

    我如何提醒 jshint 我有全局变量 即命名它们 我知道你可以做到这一点 但我不记得语法了 我在这里定义了一个全局的 function window glob1 local var 稍后像这样使用 不同的 IIFE function gl
  • 纯 JS 相当于 Jquery eq()

    jquery 的纯等价物是什么eq 例如 我怎样才能实现 class1 class2 eq 0 text 1254 在纯 JavaScript 中 要获取数组中的元素索引 可以使用 在 JavaScript 中 因此 要重现您的代码 您可以
  • Angular UI-Router:多个 URL 到单一状态

    我已经开始使用 Angular 的 ui router 并且我正在尝试弄清楚如何让多个 URL 引用单个状态 例如 orgs 12354 overview retyrns the same pages as org overview 我的
  • 如何将本地文本文件上传到文本区域(网页内)

    我是一名新手程序员 需要一些帮助来弄清楚如何将本地文本文件上传到我正在构建的网站内的文本区域 我非常精通 HTML CSS 对 Javascript JQuery 有相当的了解 而且我刚刚学习 PHP 您能提供的任何帮助我将不胜感激 我有一
  • 在 javascript 中实现固定位置会导致 Safari 滚动时出现抖动

    固定位置不适用于我的用例 因为它固定在浏览器窗口上 您可能会处于文本在屏幕右侧之外且无法到达的状态 无论如何 我尝试使用绝对定位 然后调整javascript中的 顶部 它在 Firefox 和 Chrome 中运行良好 但在 Safari
  • Javascript等待/异步执行顺序

    所以我试图把我的头脑集中在 Promise await async 上 我不明白为什么当 go 执行时 带有 finished 的警报会紧随 console log coffee 之后 当所有函数都使用等待 承诺时 为什么它只等待 getC
  • 如何使用 Javascript OAuth 库不暴露您的密钥?

    看着Twitter OAuth 库 https dev twitter com docs twitter libraries 我看到了这个注释 将 JavaScript 与 OAuth 结合使用时要小心 不要暴露你的钥匙 然后 看着jsOA
  • 如何使用 jQuery 过滤 DropDownList 中的选项

    我有 2 个 DropDownList 第一个 DropDownList 有 4 个选项 第二个 DropDownList 有 20 个选项 我想要一个选项value 1在第一个 DropDownList 中选择我在第二个 DropDown
  • javascript:完全删除top.location.hash?

    如果我的地址栏中已经有一个哈希值 例如domain com whatever 我打电话 top location hash wathever 被转换为domain com 没有任何内容 是否可以完全删除哈希值 所以没有 left 因为如果我
  • Html5画布最热门的任意形状

    我正在尝试开发可以在画布中渲染图像和文本的程序 我尝试处理画布中图像的点击 但它适用于可矩形图像 我的问题 您是否知道处理单击画布中图像的可见部分 非透明部分 的解决方案或框架 我正在寻找 ActionScript hitTestObjec

随机推荐

  • 电脑主板跳线_电脑哥教你如何接电脑主板跳线

    主板跳线接法详解 图 作为一名新手 要真正从头组装好自己的电脑并不容易 也许你知道CPU应该插哪儿 内存应该插哪儿 但遇到一排排复杂跳线的时候 很多新手都不知道如何下手 钥匙开机其实并不神秘 还记不记得你第一次见到装电脑的时候 JS将CPU
  • stm32f407 usb cdc设备无法启动问题

    最新要做一个项目 要求基于STM32F407实现USB CDC设备 首先想到的就是直接用STM32CUBEMX工具来生成 OK 话不多说 直接上过程 RCC配置 Sys配置 USB OTG FS配置 USB DEVICE配置 时钟配置 然后
  • Windows 下安装并配置Maven

    前言 Maven 翻译为 专家 内行 是Apache下的一个纯Java开发的开源项目 Maven 是一个项目管理工具 可以对Java项目进行构建 依赖管理 Maven是基于项目对象模型 POM project object model 可以
  • 输入阻抗与偏置电流

    对于高阻信号要选用FET运放 高阻信号R2和运放上的高阻并联会影响实际R2电阻值 CMRR 共模抑制比 放大电路对差模信号的电压增益与对共模信号的电压增益之比的绝对值 因为我们要抑制零漂所以共模电压增益越小越好 而差模电压增益越大越好 所以
  • pycharm上已存在某些库,但无法调用的问题解决

    如果出现pycharm上已存在openpyxl 但无法调用的时候 就是pycharm安装openpyxl库时 安装的位置与pycharm中引用python解释器的位置不一致 导致不能调用opentyxl 所以再安装openpyxl时 把项目
  • Python 绝对简明手册

    原文 简述 1 阅读须知 文中使用 gt gt gt 作为会命令行中的输出信息的前缀 对于不清楚用用途的函数可以在解释器下面输入 help 函数名 来获取相关信息 另外 自带的文档和google也是不可少的 2 基本语法 2 1 if el
  • 简历制作讲解

    简历制作讲解 前期假想 简历如同一本书 书大体分为文本结构和文本内容 一 简历文本结构 一 个人信息 必要 二 教育背景 必要 三 自我介绍 可选 四 工作经历 五 项目经历 六 技能评价 二 简历文本内容 一 个人信息 必要 必要信息 姓
  • WebTestClient使用

    介绍 WebTestClient用于测试WebFlux服务器端点的主要入口点 它具有与WebClient非常相似的API 内部大部分调用WebClient实例 主要提供测试上下文 绑定到一个服务 WebTestClient testClie
  • 解决:参考的对象类型不支持尝试的操作。 [已退出进程,代码为 4294967295]

    问题描述 win10系统下运行wsl时候显示错误 参考的对象类型不支持尝试的操作 已退出进程 代码为 4294967295 经过个人测试解决方式为关闭网易UU当前的加速 过一会就恢复正常 不需要重启
  • MySQL架构的Server层的执行过程

    1 连接器 主要负责跟客户端建立连接 获取权限 维持和管理连接 2 查询缓存 优先在缓存中进行查询 如果查到了则直接返回 如果缓存中查询不到 在去数据库中查询 3 解析器 分析器 分析器的工作主要是对要执行的SQL语句进行词法解析 语法解析
  • 基于SpringBoot+Async注解整合多线程

    提示 本文没有使用原生的创建线程方式 默认已掌握创建线程的四种方式 全文基于SpringBoot框架 要求读者掌握SpringBoot操作 本人能力有限 如有遗漏或错误 敬请指正 谢谢 文章目录 其他文章 前言 一 为什么要使用多线程 二
  • 计算机 服装生产管理的变化,服装生产管理概述.doc

    PAGE PAGE 182 目 录 TOC o n h z HYPERLINK l To 第一章 服装生产管理概述 HYPERLINK l To 第一节 服装生产概述 HYPERLINK l To 一 服装生产企业的特点 HYPERLINK
  • Yii 2.0集成七牛云

    背景知识 七牛云就是我们常说的图床 什么是图床 可以简单理解为是一种存储图片资源的服务器 本文基于Yii2简单介绍七牛云的使用 1 首先在七牛云平台创建账户 传送门 2 登陆账户之后 点击头部菜单管理控制台 进入之后 点击左侧菜单存储对象
  • 技术岗-网上测评智力题

    A 逻辑推理 1 你让工人为你工作7天 给工人的回报是一根金条 金条平分成相连的7段 你必须在每天结束时给他们一段金条 如果只许你两次把金条弄断 你如何给你 的工人付费 2 请把一盒蛋糕切成8份 分给8个人 但蛋糕盒里还必须留有一份 3 小
  • Qt Plugin

    问题 创建 Qt 插件 方法 1 QML 插件 1 qmldir plugin dll plugin qml 位于同一目录 目录名和模块名相同 2 错误列表如下 no dir no qmldir module module is not i
  • CUDA C编程3 - 并行性衡量指标

    系列文章目录 文章目录 系列文章目录 前言 一 CUDA C并行性衡量指标介绍 二 案例介绍 1 案例说明 2 案例实现 3 结果分析 总结 参考资料 前言 CUDA编程 就是利用GPU设备的并行计算能力实现程序的高速执行 CUDA内核函数
  • 相关系数R-判定系数R方的matlab实现

    相关系数 判定系数 相关系数是最早由统计学家卡尔 皮尔逊设计的统计指标 是研究变量之间线性相关程度的量 一般用字母 r 表示 由于研究对象的不同 相关系数有多种定义方式 较为常用的是皮尔逊相关系数 相关表和相关图可反映两个变量之间的相互关系
  • Table表格(antd-design组件库)简单使用

    1 Table表格 展示行列数据 2 何时使用 当有大量结构化的数据需要展现时 当需要对数据进行排序 搜索 分页 自定义操作等复杂行为时 组件代码来自 表格 Table Ant Design 3 本地验证前的准备 参考文章 react项目
  • java 正则表达式 pattern_Java—正则表达式(Pattern类和Matcher类)

    正则表达式介绍 正则表达式可以用于对字符串的处理 相当于是一个匹配字符串的模板 主要包含查找 替换 分割 提取等操作 Java中通过Pattern和Matcher类提供对正则的支持 字符处理 特殊字符处理 对于特殊字符 前面都要加上 进行转
  • 前端埋点实现

    您好 如果喜欢我的文章 可以关注我的公众号 量子前端 将不定期关注推送前端好文 前端埋点实践 介绍 1 实现自定义hook 监测组件 2 收集数据 3 前端错误捕捉 4 发送后端保存数据 5 收集数据展示 总结 介绍 这段时间博主一直在投入