1.为什么要探索
这纯属是我个人意愿,不想不明不白的使用一个东西,不求完全掌握,但想大概知道如何实现。刚进亚运项目小组,接到埋点任务,通过组内学习基本上明白了埋点API的使用,半懂半蒙的完成了埋点任务。
近期手上任务都提测了,闲下来想去探索探索我心中的几个疑问:
- 埋点是否会影响性能?
- 埋点是Ajax请求吗?
- 背后实现思想是什么?
2.如何探索?
本人没有技巧,混迹各种技术社区,俗称水群,总有大佬会说出一些你不知道的web规范、或者说新规范。其实是自己懒,不能想各种大佬一样每周都会去看看web mdn。
3.回归主题,埋点技术栈
Beacon API
Beacon API
不会延缓网页卸载,不会严重影响用户体验。
为了解决网页卸载时,异步请求无法成功的问题,浏览器特别实现了一个 Beacon API
,允许异步请求脱离当前主线程,放到浏览器进程里面发出,这样可以保证一定能发出。
navigator.sendBeacon()
方法可以保证,异步请求一定会发出;
第一个参数是请求的网址,第二个参数是发送的数据;
Beacon API 发出的是 **POST **请求。
window.addEventListener('click', function (event) {
navigator.sendBeacon('/graphql/api/v3/logs', 'event=click');
});
技术栈应用场景
- 埋点
- 异常处理
- 数据收集
- 性能上报
<html>
<script>
// emit non-blocking beacon to record client-side event
function reportEvent(event) {
var data = JSON.stringify({
event: event,
time: performance.now()
});
navigator.sendBeacon('/collector', data);
}
// emit non-blocking beacon with session analytics as the page
// transitions to background state (Page Visibility API)
document.addEventListener('visibilitychange', function() {
if (document.visibilityState === 'hidden') {
var sessionData = buildSessionReport();
navigator.sendBeacon('/collector', sessionData);
}
});
</script>
<body>
<a href='http://www.w3.org/' onclick='reportEvent(this)'>
<button onclick="reportEvent('some event')">Click me</button>
</body>
</html>
缺点:存在兼容性问题;
![image.png](https://img-blog.csdnimg.cn/img_convert/515362c3d105ff6187bbe994d69edef6.png#clientId=uee75fa70-382e-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=537&id=u73194602&margin=[object Object]&name=image.png&originHeight=1074&originWidth=2710&originalType=binary&ratio=1&rotation=0&showTitle=false&size=241861&status=done&style=none&taskId=u62877d4d-8716-4063-8d65-c062d658e8d&title=&width=1355)
Beacon 的浏览器支持情况非常好,唯一值得注意的例外是 IE 浏览器(包括 Edge)和 Opera Mini 浏览器。对于大多数情况来说,应该是没有问题的,但在尝试使用 navigator.sendBeacon 时,还是值得做下兼容测试的。如果要兼容低版本浏览器,这时候我们可以采取降级处理:
if (navigator.sendBeacon) {
// Beacon 代码
} else {
// 不支持 Beacon。也许降级到 XHR?
}
如何处理降级处理
- 采用ajax 上报
- 使用image上报
一般来说,都是采用利用image对象的方式上报错误、埋点的;使用图片发送get请求,上报信息,由于浏览器对图片有缓存,同样的请求,图片只会发送一次,避免重复上报。
代码示例
let entry = {};
function report(url, data) {
if (!url || !data) {
return;
}
// @see http://jsperf.com/new-image-vs-createelement-img
let image = document.createElement('img');
image.width = 0;
image.height = 0;
let items = [];
for (let key in data) {
if (data[key]) {
items.push(key + '=' + encodeURIComponent(data[key]));
}
}
let name = 'img_' + (+new Date());
entry[name] = image;
image.onload = image.onerror = function () {
console.log(arguments);
entry[name] =
image =
image.onload =
image.onerror = null;
delete entry[name];
};
image.src = url + (url.indexOf('?') < 0 ? '?' : '&') + items.join('&');
}
image 方式是通过将采集的数据拼接在图片请求的后面,向服务端请求一个 0*0 px 大小的图片实现的,设置它的 src 属性就可以发送数据。这种方式简单且天然可跨域,又兼容所有浏览器,没有阻塞问题,是目前比较受欢迎的前端数据上报方式。但由于是** get 请求,对上报的数据量有一定的限制,一般为 2~8 kb**。代码示例如下:
var img = new Image();img.width = 1;img.height = 1;img.src = '/sa.gif?project=default&data=xxx';
HTML5 给 **<img> 标签**
新增加了一个** **crossOrigin**
属性**,这个属性决定了_图片获取过程中是否开启跨域功能_。并且如果设置了 **crossOrigin**
这个属性,image 请求中将不带 cookie。代码示例如下:
var img = new Image();img.crossOrigin = "anonymous"
4.总结
4.1 使用img标签get请求
- 不存在AJAX跨域问题,可做跨域请求
- 很古老的标签,没有浏览器兼容问题
4.2 navigator.sendBeacon
大部分浏览器都支持navigator.sendBeacon
方法。这个方法可以用来发送一些统计和诊断的小量数据,特别时候上报统计场景。
- 数据可靠,浏览器关闭请求也照样能够发送
- **异步执行,**不会影响下一页面的加载
- API使用简单
所以当浏览器支持**navigator.sendBeacon**
方法,优先使用该方法,使用img方式降级上报。
Beacon API 在将数据从页面发送到服务端方面非常管用,尤其是在日志记录方面。浏览器支持非常广泛,它使你能够无缝地记录数据,而不会对用户的浏览体验和网站性能产生负面影响。 请求的非阻塞性意味着性能比 XHR 和 Fetch 等替代方案好得多