传统解决方案遇到的问题
- 统计脚本和其它脚本参合在一起,导致用户关闭页面过早,统计脚本还未加载/初始化完成。解决方法单独加载统计脚本,并且放在前头,让它优先加载。具体做法有:
- Nginx 在 Body 开始标签位置注入一段脚本处理。
- js 动态请求换成 <img src> 硬编码的方式发送请求
- 用户关闭或者跳出页面的时候,请求未发出。比如点击前发送日志然后立即跳转,如果不做任何优化处理,这种场景的丢失率巨高。具体解决方法:
- 阻塞式的 Ajax 请求(同步请求)
window.addEventListener('unload', function(event) {
var xhr = new XMLHttpRequest(),
xhr.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
xhr.open('post', '/log', false); // 同步请求
xhr.send(data);
});
- 暴力的死循环阻塞页面关闭
window.addEventListener('unload', function(event) {
send(data);
var now = +new Date;
while(new Date - now >= 10) {} // 阻塞 10ms
});
- 发一个图片请求阻塞
大部分浏览器都会等待图片的加载,趁这个机会把统计数据发送出去
window.addEventListener('unload', function(event) {
send(data);
(new Image).src = 'http://example.com/s.gif';
}
以上提到的几个方案都是一个原理,让浏览器继续保持阻塞状态,等数据发送出去后再跳转,这里存在的问题是:
- 少量浏览器下可能不奏效。
- 等待一会儿再跳转,用户体验上打了折扣,尤其是移动端上。
优化方案
localstorage 存储重发
针对丢失率高的场景,咱们可以先把请求日志存储在 localstorage 中,失败后在下个页面重发,并且可以添加重试机制,这样日志的完整性能很大程度上提高。
网友评论