埋点上报所需的数据可能来自四面八方,为了不影响业务,我们采用采集数据的形式单独维护埋点所需的数据,而非从不同地方传进来。
封装一个类,主要有采集和上报两个方法,通过事件名为key来对应收集的数据。
class Track {
constructor() {
this.eventDataMap = new Map();
}
collect(eventName, eventData) {
this.eventDataMap.set(eventName, eventData);
}
report(eventName) {
const eventData = this.eventDataMap.get(eventName);
fetch('xxx', {
event_name: eventName,
event_data: eventData,
}).then(() => {
this.eventDataMap.delete(eventName);
});
}
}
export default new Track();
以上程序只适合一对一场景,也就是一个eventName对应一次上报。
track.collect('EVENT_A', {tab: 'A'});
track.report('EVENT_A');
track.report('EVENT_A');
第二次上报的时候数据就没了
想要的是一对一,实际是一对多。
如果是一个事件名对应一处上报,那就简单了,它的生命周期就是收集数据、上报、回收数据。
但如果一个事件名对应多处上报,那就不知道何时回收数据了。
例如:
eventName: ‘login_click’
eventData: {btn_name:‘我的、注册、发送验证码…’, page_source:‘xxx’}
一个事件会对应不同的传参
达到埋点数据和业务数据之间的解耦,到实际上报处读取数据进行上报。
因为收集的可能是公共数据,不知道何时回收该公共数据,那他就不应该被回收。
class Track {
constructor() {
this.eventDataMap = new Map();
this.eventName = '';
this.tempPageSource = {};
this.taskQueue = [];
}
/*
* 采集数据
* 有需要在不同地方采集数据才使用
* */
collect(eventName, eventData = {}) {
const preData = this.eventDataMap.get(eventName) ?? {};
this.eventName = eventName;
this.eventDataMap.set(eventName, {
...preData,
...eventData,
});
return this;
}
/*
* 获取数据
* */
getEventData(eventName) {
return this.eventDataMap.get(eventName) ?? {};
}
/*
* 上报
* 会合并collect过的数据
* */
report(eventName, eventData = {}) {
const _eventName = eventName ?? this.eventName;
const _eventData = {
...(this.getEventData(_eventName) ?? {}),
...eventData,
};
this.addTask(_eventName, _eventData);
this.run();
}
run() {
if (!this.taskQueue.length || !mfUtil.isInit) return;
while (this.taskQueue.length) {
const task = this.taskQueue.shift();
fetch('...')
}
}
/*
*
* 由于初始化的原因可能一开始无法上报,所以加入队列
* */
addTask(eventName, eventData) {
this.taskQueue.push({
eventName,
eventData,
});
}
}
export default new Track();
如何收集一个页面来源参数“page_source”
比如点击一个按钮,跳转到另一个页面,需要记录这个按钮的名称。
如果你的页面层级只有两级,那么只需要全局维护一个“page_source”变量即可。
如果有更深的层级则不行,此时的“page_source”就是一对一的关系了,所以可以维护一个map,使页面与page_source一一对应。
<Button
name={'按钮名称'}
...
/>
const Button=({name})=>{
return <button
onClick={()=>{
track.tempPageSource=name
}}
/>
}
routeChange={()=>{
const currentName=getCurrentRoute().name
track.pageSourceMap.set(currentName,track.pageSource)