Navigator.sendBeacon() 比眉伴天荒 2022-04-23 14:18 155阅读 0赞 用户卸载网页的时候,有时需要向服务器发一些数据。很自然的做法是在`unload`事件或`beforeunload`事件的监听函数里面,使用**XMLHttpRequest**对象发送数据。但是,这样做不是很可靠,因为**XMLHttpRequest**对象是异步发送,很可能在它即将发送的时候,页面已经卸载了,从而导致发送取消或者发送失败。 解决方法就是 **AJAX** 通信改成同步发送,即只有发送完成,页面才能卸载。**但是,很多浏览器已经不支持同步的 XMLHttpRequest 对象了(即open()方法的第三个参数为false)**。 window.addEventListener('unload', logData, false); function logData() { var client = new XMLHttpRequest(); // 第三个参数表示同步发送 client.open('POST', '/log', false); client.setRequestHeader('Content-Type', 'text/plain;charset=UTF-8'); client.send(analyticsData); } 上面代码指定XMLHttpRequest同步发送,很多浏览器都已经不支持这种写法。 同步通信有几种变通的方法。一种做法是新建一个`<img>`元素,数据放在**src**属性,作为 URL 的查询字符串,这时浏览器会等待图片加载完成(服务器回应),再进行卸载。另一种做法是创建一个循环,规定执行时间为几秒钟,在这几秒钟内把数据发出去,然后再卸载页面。 这些做法的共同问题是,**卸载的时间被硬生生拖长了,后面页面的加载被推迟了,用户体验不好**。 为了解决这个问题,浏览器引入了`Navigator.sendBeacon()`方法。这个方法还是异步发出请求,但是请求与当前页面脱钩,作为浏览器的任务,因此可以保证会把数据发出去,不拖延卸载流程。 window.addEventListener('unload', logData, false); function logData() { navigator.sendBeacon('/log', analyticsData); } `Navigator.sendBeacon`方法接受两个参数,第一个参数是目标服务器的 URL,第二个参数是所要发送的数据(可选),可以是**任意类型**(字符串、表单对象、二进制对象等等)。 navigator.sendBeacon(url, data) 这个方法的返回值是一个布尔值,成功发送数据为true,否则为false。 该方法发送数据的 HTTP 方法是 **POST**,**可以跨域**,类似于表单提交数据。**它不能指定回调函数**。 下面是一个例子。 // HTML 代码如下 // <body "analytics('start')" onunload="analytics('end')"> function analytics(state) { if (!navigator.sendBeacon) return; var URL = 'http://example.com/analytics'; var data = 'state=' + state + '&location=' + window.location; navigator.sendBeacon(URL, data); }
还没有评论,来说两句吧...