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


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

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

    原因1:关闭浏览器时一定会触发事件吗?如果不一定,那什么条件下才不触发呢?

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

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

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

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


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

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

    一些浏览器将该事件返回的字符串显示在弹出窗上。但从Firefox 4、 Chrome 51、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()或是更好的选择。 

  • 相关阅读:
    20150515
    20150509
    20150507
    好用的log打印类
    20150429
    Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
    word无法切换中文输入法的解决方法
    20140917设置动态壁纸
    WCF入门教程(三)定义服务协定--属性标签
    WCF入门教程(二)从零做起-创建WCF服务
  • 原文地址:https://www.cnblogs.com/yubin-/p/12801302.html
Copyright © 2020-2023  润新知