埋点上报的主要信息
- 埋点的标识信息: eventId, eventType, pv(page view), uv(uset pv),
- 业务信息:sku
- 通用的设备信息/用户消息: userId, deviceId, userAgent, timeStamp, localtion
埋点上报的分类
- 实时上班: 立发送请求
- 延时上报: 依托于防抖或者在浏览器空闲时间或者页面卸载前统一上报,上报失败后可以加补偿措施
埋点的实现方式
- 代码埋点
- 无埋点
- 可视化埋点
代码埋点上报的实现方案
上报方案实现后,只需要提供一个需要上报的数据,和上报的最终操作即可,内部逻辑的封装就是上报的方案
import { debounce } from 'lodash'
interface RequiredData {
timestamp: number | string
}
// 存储逻辑
class TaskQueueStorableHelper<T extends RequiredData = any>{
public static getInstance<T extends RequiredData = any>(){
if(!this.instance){
this.instance = new TaskQueueStorableHelper<T>()
}
return this.instance
}
protected store: any = null
private STORAGE_KEY = 'lubai_store'
private static instance: TaskQueueStorableHelper | null = null
constructor() {
const localStorageValue = localStorage.getItem(this.STORAGE_KEY)
if(localStorageValue){
this.store = JSON.parse(localStorageValue)
}
}
get queueData(){
return this.store.queueData || []
}
set queueData(queueData: T[]){
this.store = {
...this.store,
queueData: this.queueData.sort((a,b) => Number(a.timestamp) - Number(b.timestamp))
}
localStorage.setItem(this.STORAGE_KEY, JSON.stringify(this.store))
}
}
// 功能函数,获取要上报的数据,同时提供具体上报操作的接口
export abstract class AsyncTaskQueue<T extends RequiredData = any>{
private get storableService(){
return TaskQueueStorableHelper.getInstance<T>()
}
private get queueData(){
return this.storableService.queueData
}
private set queueData(value: T[]){
this.storableService.queueData = value
if(value.length){
this.debounceRun()
}
}
protected debounceRun = debounce(this.run.bind(this), 1000)
protected abstract consumeTaskQueue(data: T[]): Promise<any>
protected addTask(data: T | []){
this.queueData = this.queueData.concat(data)
}
private run(){
const currentDataList = this.queueData
if(currentDataList.length){
this.queueData = []
this.consumeTaskQueue(currentDataList)
}
}
}
无埋点方案
window.addEventListener('click', (e) => {
const target = e.target
const xPath = getXPath(e.target)
console.log(xPath)
})
function getXPath(element){
if(element.id){
return `//*[@id=\'${element.id}'\]`
}
if(element == document.body){
return `/html/${element.tagName.toLowerCase()}`
}
let currentIndex = 1
let siblings = element.parentNode.childNodes
for(let sibling of siblings){
if(sibling === element){
return getXPath(element.parentNode) + '/' + element.tagName.toLowerCase() + '[' + currentIndex + ']'
} else if(sibling.nodeType === 1 && sibling.tagName === element.tagName){
currentIndex++
}
}
}