> For the complete documentation index, see [llms.txt](https://tech.banchengyun.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://tech.banchengyun.com/archives/frontend/tracking.md).

# 前端埋点

## 前端埋点

> 前言：太良日常的工作，很大一部分是跟进线上用户的问题，所以以下类型的对话就成了频率非常高的存在。

![img](https://scrm0.cdn.banchengyun.com/material/9c053d93669be69cb8b06b92e91a7f69890dc6f3.png)

那就引发了一个思考，我怎么在用户发生错误，或者进行某种行为的时候，收集到他的动作与一系列可分析的内容？答案就是前端的埋点。

### 埋点的目的

获取用户行为以及跟踪产品在用户端的使用情况，并以监控数据为基础，指明产品优化的方向。

前端监控可以分为三类：数据监控、性能监控和异常监控。

### (1) 数据监控

数据监控，顾名思义就是监听用户的行为。常见的数据监控包括：

* PV/UV:PV(page view)，即页面浏览量或点击量。UV:指访问某个站点或点击某条新闻的不同IP地址的人数
* 用户在每一个页面的停留时间
* 用户通过什么入口来访问该网页
* 用户在相应的页面中触发的行为

**统计这些数据是有意义的，比如我们知道了用户来源的渠道，可以促进产品的推广，知道用户在每一个页面停留的时间，可以针对停留较长的页面，增加广告推送等等。**

### (2) 性能监控

性能监控指的是监听前端的性能，主要包括监听网页或者说产品在用户端的体验。常见的性能监控数据包括：

* 不同用户，不同机型和不同系统下的首屏加载时间、白屏时间
* http等请求的响应时间
* 静态资源整体下载时间
* 页面渲染时间
* 页面交互动画完成时间

**这些性能监控的结果，可以展示前端性能的好坏，根据性能监测的结果可以进一步的去优化前端性能，比如兼容低版本浏览器的动画效果，加快首屏加载等等。**

### (3) 异常监控

此外，产品的前端代码在执行过程中也会发生异常，因此需要引入异常监控。及时的上报异常情况，可以避免线上故障的发上。虽然大部分异常可以通过try catch的方式捕获，但是比如内存泄漏以及其他偶现的异常难以捕获。常见的需要监控的异常包括：

* Javascript的异常监控
* 样式丢失的异常监控。

## 埋点分为什么？

![img](https://scrm0.cdn.banchengyun.com/material/d5ebdd789eccdc579c1dfacbe1d1ed3e84703f1c.png)

### 手动埋点

```html
// 手动埋点也叫做代码埋点，在每一处需要的地方，都加一段上报代码逻辑，统计用户的关键行为。

// 实现起来最快，收集到的内容可高度自定义，但影响代码的阅读体验，且散落的代码不方便管理，代码越来越像这样，谁接手谁倒霉，下面我们来看实际代码
```

![img](https://scrm0.cdn.banchengyun.com/material/e8f613de0d75e25601a17c45c8938ece900af88f.png)

### 可视化埋点

通过可视化交互的手段，代替上述的代码埋点。 将业务代码和埋点代码分离，提供一个可视化交互的页面，输入为业务代码， 通过这个可视化系统，可以在业务代码中自定义的增加埋点事件等等， 最后输出的代码耦合了业务代码和埋点代码。

缺点就是可以埋点的控件有限，不能手动定制。 可视化埋点听起来比较高大上，实际上跟代码埋点还是区别不大。 也就是用一个系统来实现手动插入代码埋点的过程。 比如国外比较早做可视化的是Mixpanel， 国内较早支持可视化埋点的有TalkingData、诸葛 IO，2017年腾讯的MTA也宣布支持可视化埋点；

相比于手动埋点更新困难，埋点成本高的问题，可视化埋点优化了移动运营中数据采集的流程， 能够支持产品运营随时调整埋点，无需再走发版流程，直接把配置结果推入到前端， 数据采集流程更简化，也更方便产品的迭代。可视化埋点中多数基于Xpath的方案， XPath 是一门在 XML 文档中查找信息的语言，XPath 可用来在 XML 文档中对元素和属性进行遍历。

### 无痕埋点

无痕埋点也叫全埋点，通过控件绑定触发事件，事件被触发的时候系统会有相应的事件让开发者处理这些行为。

### 实现埋点

#### 最简单的埋点

```js
// 通过window对象的onerror监听，获取所有报错的内容。
window.onerror = function (message, source, lineno, colno, error) {
    console.log(message);
    console.log(source);
    console.log(lineno);
    console.log(colno);
    console.log(error);
};

console.log(test);
```

#### 晋级 => 实现一个简单的无痕埋点

> 借助createElement，通过劫持的形式主动上报，具体看代码

```jsx
// js
import React from 'react'

export const initTrack = ({ onClickEvent }) => {

  const createElement = React.createElement

  const handleEditClick = props => {
    const click = props.onClick
    console.log(props)
    props.onClick = e => {
      onClickEvent && onClickEvent(props.data)
      click && click(e)
    }
  }

  React.createElement = function () {
    const args = Array.prototype.slice.call(arguments)
    console.log(args)
    let zhihong = args[1]

    if (zhihong && zhihong.data) {
      zhihong = handleEditClick(zhihong)
    }
    return createElement.apply(null, args)
  }
}
```

```jsx
// jsx
import React, { useEffect } from 'react'

import { initTrack } from './track'

const Test = () => {
  initTrack({
    onClickEvent: data => {
      // 我在这里 给后端上报咯～～～
      console.warn(data)
    }
  })

  return (
    <>
      <a data={{ test: 2 }}>222</a>
      <div
        style={{ fontSize: 40 }}
        onClick={() => {
          console.log('点击')
        }}
        data={{
          a: 1,
          b: 2
        }}
      >
        我要点击
      </div>
    </>
  )
}

export default Test
```
