数据上报
当收集到数据时何时上报以及如何上报,情况如下:
- 获得数据时,可以立即上报,也可以把数据存储在本地,等数据到达一定的数量时上报,或者每隔一段时间上报一次
- 使用SDK或者调用ajax上报时,一般会有回调函数,上报成功时,使用时间戳timestamp等唯一标识从本地存储移除
- 一般Google,FaceBook等使用GIF上报,Google和FaceBook分别提供了gtag和fbq等API,其中FaceBook对于上报的方式判断更为详细也有可能使用POST上报
- 当页面跳转时,会导致请求失败,一般可以借助回调函数的机制或者navigator.sendBeacon。当然也可以利用数据存储在本地,在跳转页面之后再进行上报。或者阻止页面的跳转,等数据上报成功之后,在进行跳转(此方式不建议)
GIF上报
- 避免跨域
- 防止阻塞页面加载,影响用户体验:不会阻塞页面加载,影响用户的体验,只要new Image对象就好了,一般情况下也不需要append到DOM中,通过它的onerror和onload事件来检测发送状态
- 相比PNG/JPG,GIF的体积最小:最小的BMP文件需要74个字节,PNG需要67个字节,而合法的GIF,只需要43个字节。同样的响应,GIF可以比BMP节约41%的流量,比PNG节约35%的流量。
<script type="text/javascript">
var thisPage = location.href;
var referringPage = (document.referrer) ? document.referrer : "none";
var beacon = new Image();
beacon.src = "http://www.example.com/logger/beacon.gif?page=" + encodeURI(thisPage)
+ "&ref=" + encodeURI(referringPage);
</script>
Navigator.sendBeacon()
用户卸载网页的时候,有时需要向服务器发一些数据。很自然的做法是在unload事件或beforeunload事件的监听函数里面,使用XMLHttpRequest对象发送数据。但是,这样做不是很可靠,因为XMLHttpRequest对象是异步发送,很可能在它即将发送的时候,页面已经卸载了,从而导致发送取消或者发送失败。
解决方法就是unload事件里面,加一些很耗时的同步操作。这样就能留出足够的时间,保证异步 AJAX 能够发送成功。
function log() {
let xhr = new XMLHttpRequest();
xhr.open('post', '/log', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('foo=bar');
}
window.addEventListener('unload', function(event) {
log();
// a time-consuming operation
for (let i = 1; i < 10000; i++) {
for (let m = 1; m < 10000; m++) { continue; }
}
});
在用户点击时,延迟跳转。
const clickTime = 350;
const theLink = document.getElementById('target');
function log() {
let xhr = new XMLHttpRequest();
xhr.open('post', '/log', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('foo=bar');
}
theLink.addEventListener('click', function (event) {
event.preventDefault();
log();
setTimeout(function () {
window.location.href = theLink.getAttribute('href');
}, clickTime);
})
navigator.sendBeacon(url, data)
- url: 表明
data将要被发送到的网络地址 - data: 将要发送的
ArrayBuffer、ArrayBufferView、Blob、DOMString、FormData或URLSearchParams类型的数据 返回值一个布尔值,成功发送数据为true, 否则为false。 发送该数据的方法是POST,可以跨域,类似于表单提交数据,不能指定回调函数。
避免使用unload和beforeunload
许多网站使用 unload 或 beforeunload 事件以在会话结束时发送统计数据。然而这是不可靠的,在许多情况下(尤其是移动设备)浏览器不会产生 unload、beforeunload 或 pagehide 事件。下面列出了不触发上述事件的情况:
- 用户点击了一条系统通知,切换到另一个 App。
- 用户进入任务切换窗口,切换到另一个 App。
- 用户点击了 Home 按钮,切换回主屏幕。
- 操作系统自动切换到另一个 App(比如,收到一个电话)
此外,unload 事件与现代浏览器实现的往返缓存(bfcache)不兼容。在部分浏览器(如:Firefox)通过在 bfcache 中排除包含 unload 事件处理器的页面来解决不兼容问题,但这存在性能损失。其它浏览器,例如 Safari 和 Android 上的 Chrome 浏览器则采取用户在同一标签页下导航至其它页面时不触发 unload 事件的方法来解决不兼容问题。
Firefox 也会在 bfcache 中排除包含 beforeunload 事件处理器的页面。
visibilitychange
通过监听网页的可见性,可以预判网页的卸载,还可以用来节省资源,减缓电能的消耗。比如,一旦用户不看网页,下面这些网页行为都是可以暂停的。
- 对服务器的轮询
- 网页动画
- 正在播放的音频或视频
document.visibilityState
在document对象上,新增了一个document.visibilityState属性。该属性返回一个字符串,表示页面当前的可见性状态,共有三个可能的值。
hidden:页面彻底不可见。visible:页面至少一部分可见。prerender:页面即将或正在渲染,处于不可见状态。
hidden状态和visible状态是所有浏览器都必须支持的。prerender状态只在支持"预渲染"的浏览器上才会出现,比如 Chrome 浏览器就有预渲染功能,可以在用户不可见的状态下,预先把页面渲染出来,等到用户要浏览的时候,直接展示渲染好的网页。
document.visibilityState属性为hidden,以下四种情况
- 浏览器最小化。
- 浏览器没有最小化,但是当前页面切换成了背景页。
- 浏览器将要卸载(unload)页面。
- 操作系统触发锁屏屏幕。
document.hidden
该属性只读,返回一个布尔值,表示当前页面是否可见。
当document.visibilityState属性返回visible时,document.hidden属性返回false;其他情况下,都返回true。
// 代码示例
document.addEventListener('visibilitychange', function () {
// 用户离开了当前页面
if (document.visibilityState === 'hidden') {
document.title = '页面不可见';
}
// 用户打开或回到页面
if (document.visibilityState === 'visible') {
document.title = '页面可见';
}
});
以上全部内容,如有疑问,欢迎指正。