在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:异步请求发送失败了吗?
必定失败。缘由发送异步请求后,随即关闭了浏览器,这时候此次请求的”三次握手”的”第三次握手”,客户主机便不会响应服务器主机,这也就成了一个失败的请求。如图所示。
第三次握手失败
那么有什么解决办法吗?
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()或是更好的选择。