在页面关闭时,前端上传监控数据的4个解决方案

概览
本文以 “前端监控上报数据” 的业务场景,重点解析在 页面实例关闭 时,如何将监控数据上传到服务端的解决方案。
其中,涉及到4种方案,分别为:

同步XMLHttpRequest
img.src
navigator.sendBeacon
fetch keepalive
同步XMLHttpRequest
const data = JSON.stringify({
     time: performance.now()
   });

var xhr = new XMLHttpRequest();

// 第三个参数false,表示当前请求是同步
xhr.open('post', 'http://api.wangxiaokai.vip/test', false);

xhr.setRequestHeader('content-type', 'application/json');

xhr.onreadystatechange = function() {
 // 发送成功后,页面已销毁,所以这里执行不了
}

xhr.send(data);

为什么同步XMLHttpRequest可以在页面关闭时上传数据?
同步请求阻止代码的执行,这会导致屏幕上出现“冻结”和无响应的用户体验。

然而,在新版的chrome(版本号大于80)已经不支持。
以下是官方的公告片段:

Chrome now disallows synchronous calls to XMLHTTPRequest() during page dismissal when the page is being navigated away from or is closed by the user. This applies to beforeunload, unload, pagehide, and visibilitychange.

详细解释可阅读 Disallow Synchronous XMLHTTPRequest\(\) in Page Dismissal[2]

缺点
用户体验差,会阻塞页面切换
只有旧版的浏览器支持
无法读取reponse的返回值
img.src
创建一个<img>元素,并设置src。大部分的浏览器,都会延迟卸载当前页面,优先加载图像。

var data = JSON.stringify({
   time: performance.now()
 });
 
const img = new Image();
img.src = `http://api.wangxiaokai.vip/test?${JSON.stringify(data)}`;

缺点
数据传输不可靠,有可能浏览器卸载当前页面,直接杀掉图像请求
只能发起GET请求
数据大小有限制
navigator.sendBeacon
通过HTTP POST请求,将少量数据使用异步的方式,发送到服务端。

function reportEvent() {
 const url = 'http://api.wangxiaokai.vip/test';
 const data = JSON.stringify({
   time: performance.now()
 });
 
 navigator.sendBeacon(url, data);
}

document.addEventListener('visibilitychange', function() {
 if (document.visiblityState === 'hidden') {
   reportEvent();
 }
});






发送的时机
浏览器端自动判断合适的时机进行发送

是否会产生阻塞或影响页面性能?
不会产生阻塞,影响当前页面的卸载。
不影响下个新页面的加载,不存在性能问题。
另外,数据传输可靠。

语法
navigator.sendBeacon(url);
navigator.sendBeacon(url, data);

参数解析
url:接收请求的网络地址
data:请求中携带的数据,数据格式可选:ArrayBuffer,ArrayBufferView,Blob,DomString,FormData,URLSearchParams
返回值
当浏览器将数据成功加入传输队列时,sendBeacon方法会返回true,否则返回false。

注意返回值的时机:成功加入传输队列,而不是服务端的处理成功后的返回。

缺点
只能发起POST请求
无法自定义请求头参数
数据大小有限制 (Chrome限制大小为64kb)
只能在window事件visibilitychange和beforeunload中使用,其他事件中回调,会丢失数据。
兼容性



fetch keepalive
MDN web docs的描述如下 :

The keepalive option can be used to allow the request to outlive the page. Fetch with the keepalive flag is a replacement for the `Navigator.sendBeacon()`[3] API.

标记keepalive的fetch请求允许在页面卸载后执行。

const url = 'http://api.wangxiaokai.vip/test';
const data = JSON.stringify({
   time: performance.now()
 });
 
fetch(url, {
 method: 'POST',
 body: data,
 headers: {
  'Content-Type': 'application/json'
 },
 keepalive: true,
});

兼容性



参考
Disallow Synchronous XMLHTTPRequest\(\) in Page Dismissal[4]
fetch\(\)[5]
You May Not Know Beacon[6]

关于本文:

来源:我是leon

https://juejin.cn/post/7106365076197605413

作者:leon


欢迎关注微信公众号 :前端Q