@@ -713,27 +713,58 @@ function loadEnd(e) {
713
713
714
714
用户卸载网页的时候,有时需要向服务器发一些数据。很自然的做法是在` unload ` 事件或` beforeunload ` 事件的监听函数里面,使用` XMLHttpRequest ` 对象发送数据。但是,这样做不是很可靠,因为` XMLHttpRequest ` 对象是异步发送,很可能在它即将发送的时候,页面已经卸载了,从而导致发送取消或者发送失败。
715
715
716
- 解决方法就是 AJAX 通信改成同步发送,即只有发送完成,页面才能卸载。但是,很多浏览器已经不支持同步的 XMLHttpRequest 对象了(即 ` open() ` 方法的第三个参数为 ` false ` ) 。
716
+ 解决方法就是` unload ` 事件里面,加一些很耗时的同步操作。这样就能留出足够的时间,保证异步 AJAX 能够发送成功 。
717
717
718
718
``` 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' );
727
724
}
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
+ });
728
734
```
729
735
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
+ ```
731
762
732
- 同步通信有几种变通的方法。一种做法是新建一个 ` <img> ` 元素,数据放在 ` src ` 属性,作为 URL 的查询字符串,这时浏览器会等待图片加载完成(服务器回应),再进行卸载。另一种做法是创建一个循环,规定执行时间为几秒钟,在这几秒钟内把数据发出去,然后再卸载页面 。
763
+ 上面代码使用 ` setTimeout ` ,拖延了350毫秒,才让页面跳转,因此使得异步 AJAX 有时间发出 。
733
764
734
765
这些做法的共同问题是,卸载的时间被硬生生拖长了,后面页面的加载被推迟了,用户体验不好。
735
766
736
- 为了解决这个问题,浏览器引入了` Navigator.sendBeacon() ` 方法。这个方法还是异步发出请求,但是请求与当前页面脱钩,作为浏览器的任务 ,因此可以保证会把数据发出去,不拖延卸载流程。
767
+ 为了解决这个问题,浏览器引入了` Navigator.sendBeacon() ` 方法。这个方法还是异步发出请求,但是请求与当前页面线程脱钩,作为浏览器进程的任务 ,因此可以保证会把数据发出去,不拖延卸载流程。
737
768
738
769
``` javascript
739
770
window .addEventListener (' unload' , logData, false );
0 commit comments