Skip to content

Commit ec49c63

Browse files
committed
docs(bom): edit xmlhttprequest
1 parent 729c20b commit ec49c63

File tree

1 file changed

+43
-12
lines changed

1 file changed

+43
-12
lines changed

docs/bom/xmlhttprequest.md

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -713,27 +713,58 @@ function loadEnd(e) {
713713

714714
用户卸载网页的时候,有时需要向服务器发一些数据。很自然的做法是在`unload`事件或`beforeunload`事件的监听函数里面,使用`XMLHttpRequest`对象发送数据。但是,这样做不是很可靠,因为`XMLHttpRequest`对象是异步发送,很可能在它即将发送的时候,页面已经卸载了,从而导致发送取消或者发送失败。
715715

716-
解决方法就是 AJAX 通信改成同步发送,即只有发送完成,页面才能卸载。但是,很多浏览器已经不支持同步的 XMLHttpRequest 对象了(即`open()`方法的第三个参数为`false`
716+
解决方法就是`unload`事件里面,加一些很耗时的同步操作。这样就能留出足够的时间,保证异步 AJAX 能够发送成功
717717

718718
```javascript
719-
window.addEventListener('unload', logData, false);
720-
721-
function logData() {
722-
var client = new XMLHttpRequest();
723-
// 第三个参数表示同步发送
724-
client.open('POST', '/log', false);
725-
client.setRequestHeader('Content-Type', 'text/plain;charset=UTF-8');
726-
client.send(analyticsData);
719+
function log() {
720+
let xhr = new XMLHttpRequest();
721+
xhr.open('post', '/log', true);
722+
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
723+
xhr.send('foo=bar');
727724
}
725+
726+
window.addEventListener('unload', function(event) {
727+
log();
728+
729+
// a time-consuming operation
730+
for (let i = 1; i < 10000; i++) {
731+
for (let m = 1; m < 10000; m++) { continue; }
732+
}
733+
});
728734
```
729735

730-
上面代码指定`XMLHttpRequest`同步发送,很多浏览器都已经不支持这种写法。
736+
上面代码中,强制执行了一次双重循环,拖长了`unload`事件的执行时间,导致异步 AJAX 能够发送成功。
737+
738+
类似的还可以使用`setTimeout`。下面是追踪用户点击的例子。
739+
740+
```javascript
741+
// HTML 代码如下
742+
// <a id="target" href="https://baidu.com">click</a>
743+
const clickTime = 350;
744+
const theLink = document.getElementById('target');
745+
746+
function log() {
747+
let xhr = new XMLHttpRequest();
748+
xhr.open('post', '/log', true);
749+
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
750+
xhr.send('foo=bar');
751+
}
752+
753+
theLink.addEventListener('click', function (event) {
754+
event.preventDefault();
755+
log();
756+
757+
setTimeout(function () {
758+
window.location.href = theLink.getAttribute('href');
759+
}, clickTime);
760+
});
761+
```
731762

732-
同步通信有几种变通的方法。一种做法是新建一个`<img>`元素,数据放在`src`属性,作为 URL 的查询字符串,这时浏览器会等待图片加载完成(服务器回应),再进行卸载。另一种做法是创建一个循环,规定执行时间为几秒钟,在这几秒钟内把数据发出去,然后再卸载页面
763+
上面代码使用`setTimeout`,拖延了350毫秒,才让页面跳转,因此使得异步 AJAX 有时间发出
733764

734765
这些做法的共同问题是,卸载的时间被硬生生拖长了,后面页面的加载被推迟了,用户体验不好。
735766

736-
为了解决这个问题,浏览器引入了`Navigator.sendBeacon()`方法。这个方法还是异步发出请求,但是请求与当前页面脱钩,作为浏览器的任务,因此可以保证会把数据发出去,不拖延卸载流程。
767+
为了解决这个问题,浏览器引入了`Navigator.sendBeacon()`方法。这个方法还是异步发出请求,但是请求与当前页面线程脱钩,作为浏览器进程的任务,因此可以保证会把数据发出去,不拖延卸载流程。
737768

738769
```javascript
739770
window.addEventListener('unload', logData, false);

0 commit comments

Comments
 (0)