监听浏览器关闭事件的解决方案

在web项目开发中,关于浏览器关闭事件有两个很常见的问题:为何我没有监听浏览器关闭事件? 我监听到了这个事件,但写在事件里的异步请求为何发送不成功?ios

缘由分析:这两个问题无外乎两个缘由:浏览器关闭事件未被触发 和 异步请求发送失败。web

缘由1:关闭浏览器时必定会触发事件吗?若是不必定,那什么条件下才不触发呢?ajax

与浏览器关闭事件相关事件有onunload和onbeforeunload两个。区别在于onbeforeunload在onunload以前执行,它还能够阻止onunload的执行。所以咱们着重关注onbeforeunload事件。简单科普一下onbeforeunload事件。axios

当窗口即将被卸载(关闭)时,会触发该事件.此时页面文档依然可见,且该事件的默认动做能够被取消. 该函数应当返回一个字符串,当返回的字符串不为null或者undefined时,弹出确认窗口让用户自行选择是否关闭当前页面。一些浏览器将该事件返回的字符串显示在弹出窗上。promise

 

既然“当窗口即将被卸载(关闭)时,会触发该事件“,那也就是说只要我关闭快就必定会触发该事件喽?然而当关闭浏览器时,未必必定会触发onbeforeunload事件。MDN上关于这个事件的触发条件是这样描述的。浏览器

为避免意外弹出窗口,除非页面已与之交互,不然浏览器可能不会显示在beforeunload事件中建立的提示,甚至根本不会显示它们。服务器


 那何时算是非与之交互呢?这里举个例子,一个页面连着刷新两次,第二次刷新时,就认为非与之交互,就不会触发onbeforeunload事件。,同时对于触发条件,各个浏览器之间也存在差别。具体差别汇总表以下:app

说明一下,浏览器关闭事件(onbeforeunload)里已经不能够自定义弹出窗信息了。MDN中明确写道:异步

一些浏览器将该事件返回的字符串显示在弹出窗上。但从Firefox 四、 Chrome 5一、Opera 38 和Safari 9.1开始,通用确认信息代替事件返回的字符串。函数

缘由2:异步请求发送失败了吗? 

必定失败。缘由发送异步请求后,随即关闭了浏览器,这时候此次请求的”三次握手”的”第三次握手”,客户主机便不会响应服务器主机,这也就成了一个失败的请求。如图所示。

 

第三次握手失败

 

那么有什么解决办法吗?

  1. 关闭浏览器时发送同步请求,来保证请求发送完成。可是这样一来会产生以下问题:

a)      页面延迟几秒后再关闭,体验糟糕。

b)      XMLHttpRequest规范中禁止在这个事件处理器中同步调用接口。

使用 XMLHttpRequest 发送同步请求的方式已经计划从规范中删除,再也不建议开发者使用。

这个时候不熟悉XMLHttpRequest的同窗也许会问:等一下,个人代码里根本就没有XMLHttpRequest这个对象,因此他的规范凭什么约束我?

相信你项目里调用接口时已经用到了ajax库,或者axios库。其实现有的ajax库都是对XMLHTTPRequest对象的一种封装,而axios是经过promise实现对ajax技术的一种封装,这样一来一切都说得通了。原来咱们都在直接或者间接的使用着XMLHttpRequest对象。

2.Fetch 的keepalive属性

Fetch API提供了一套健壮的与服务器端交互的方式,提供了跨越不一样平台 API 的一致接口。它提供了一个keepalive属性,保证无论发送请求的页面关闭与否,请求都会持续直到结束。不过上传数据的限制是64 KB。写法以下:

window.addEventListener(‘onbeforeunload’, {
fetch('/siteAnalytics', {
  method: 'POST',
  body: getStatistics(),
  keepalive: true
});
}

那经过Fetch API调用的接口如何添加头信息呢?以添加token为例,如下代码亲测有效。

window.addEventListener(‘onbeforeunload’, {
fetch('/siteAnalytics', {
  method: 'POST',
  body: 'id=' + id + '&name=' + name + '&age=' + age,
  headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
          token:’ myToken’
          },
  keepalive: true
});
}

3.SendBeacon()

 SendBeacon() 方法可用于经过HTTP将少许数据异步传输到Web服务器。该方法底层的使用的是 Fetch API,这样就能明白为何它也有少许数据(64 KB)的上传数据限制,也能明白为何它还能在页面卸载后继续请求。它的主要优势是简单,只要用一行代码就能搞定。

window.addEventListener('unload', {
  navigator.sendBeacon('/siteAnalytics', getStatistics());
}

总结一下,对于浏览器关闭事件,若是咱们与页面未发生交互,那么当窗口即将被卸载(关闭)时便不会触发onbeforeunload事件;同时一些主流浏览器,从某个版本开始,也不容许咱们自定义弹窗信息来给予用户友好提示了;若是想在该事件中发送请求,相对于使用XMLHttpRequest对象来讲,fetch API或者sendBeacon()或是更好的选择。 

相关文章
相关标签/搜索