并行请求合并
埋点通常在用户进入页面后会触发多个请求,例如页面浏览量(PV)、各个模块元素的曝光情况,以及接口请求的上报。这种情况可能导致在进行某个操作时,页面同时发送许多重复的请求。为了解决这个问题,与后端讨论后,决定支持将埋点请求合并,即允许接口以数组形式一次性上报多个埋点数据。
因此,前端需要实现一个自动合并请求的函数,该函数能够在一个指定的时间窗口内收集相同类型的请求,并在窗口结束时将它们合并为一个请求一起发送。这样不仅可以减少请求数量,还能提高性能和数据处理的效率。
// 假设这是一个发送埋点数据的函数
async function sendTrackingData(params) {
// 模拟发送请求
console.log('Sending tracking data:', params);
return Promise.resolve(params); // 返回 Promise
}
// 创建自动合并请求的函数
const autoMergedRequest = createAutoMergedRequest(sendTrackingData, 200);
// 使用示例
function trackPageView() {
autoMergedRequest({ type: 'page_view', page: 'home' });
}
function trackElementExposure(elementId) {
autoMergedRequest({ type: 'element_exposure', elementId });
}
// 模拟用户行为
trackPageView(); // 记录页面浏览量
trackElementExposure('banner'); // 记录元素曝光
trackElementExposure('sidebar'); // 记录另一个元素曝光
trackElementExposure('footer'); // 记录另一个元素曝光
// 这里可以继续调用 autoMergedRequest 进行其他埋点
function createAutoMergedRequest(fn, windowMs = 200) {
let queue = [];
let timer = null;
async function submitQueue() {
timer = null; // 清空计时器以接受后续请求
const _queue = [...queue];
queue = []; // 清空队列
try {
const list = await fn(_queue.map((q) => q.params));
_queue.forEach((q1, i) => {
q1.resolve(list[i]);
});
} catch (err) {
_queue.forEach((q2) => {
q2.reject(err);
});
}
}
return (params) => {
if (!timer) {
// 如果没有开始窗口期,则创建
timer = setTimeout(() => {
submitQueue();
}, windowMs);
}
return new Promise((resolve, reject) => {
queue.push({
params,
resolve,
reject,
});
});
};
}