论如何保证在离开页面时顺利发出请求的几种方式

282 阅读3分钟

前言

看到标题,其实各位前端er应该就知道这篇文章主要实现的是什么功能了。

简单说一下就是,在用户关闭页面,或者跳转链接时,我们需要发出一个请求,但是发出请求的时间不一定会比离开页面的时间快,浏览器在页面进入**Discarded** 状态时,为了节约资源,会丢弃当前页面的任务,事件回调等等,具体的东西这里不细说,关于页面生命周期的事情,大家看这里

例子

这里我用跳转链接举个例子

在a.html中有一个a链接指向b.html a链接点击事件中会发出一个请求

  <a id="a" href="./b.html">TO b</a>
  <script>
    const sendFetch = () => {
      fetch('http://localhost:3000/restful/info',{
        method: 'post'
      })
    }
    const handleToB = (e) => {
      sendFetch()
      
    }
    a.addEventListener('click',handleToB)
  </script>

点击后,看下控制台效果

image.png

看起来成功了,没问题呀。but,让我们在控制台把网络改慢点

image.png

再重新点一次链接,看看效果

image.png

果不其然,之前能成功只是因为网速够快,在真实场景下,谁能保证客户的网络呢 φ(* ̄0 ̄) 。

所以这里记录下解决这个问题的几个办法

sendBeacon

这绝对是最出名的解决方案了,Navigator.sendBeacon() 的诞生就是为了解决这种问题的

  • 数据发送是可靠的。
  • 数据异步传输。
  • 不影响下一导航的载入。

当然他有他的一些限制,他用的是post请求,如果传输数据,需要对对象数据进行json.stringify处理,我们看下修改后的代码

<script>
    const sendFetch = () => {
      fetch('http://localhost:3000/restful/info',{
        method: 'post'
      })
    }
    const sendBeacon = () => {
      navigator.sendBeacon('http://localhost:3000/restful/info')
    }
    const handleToB = (e) => {
      // sendFetch()
      sendBeacon()
    }
    a.addEventListener('click',handleToB)
  </script>

效果图

image.png 我们可以看到,接口没有取消,状态是(未知)unknow,因为这个请求是a.html发出的,a.html这个页面已经离开了,浏览器不会等待接口的响应,sendBeacon只是确保他会发出去。

说一下他的优缺点

  • 优点
  • 资源占用少
  • 不受跨域影响

缺点

  • 需要对数据进行处理(问题不大)

fetch

第二个方法,还是fetch,哈哈哈哈哈哈,没错,他还是可以的

fetch有一个属性,keepalive,将这个属性设置成true后,浏览器会保持这个请求,不会像之前一样,离开页面就取消请求,看一下代码

<script>
    const sendFetch = () => {
      fetch('http://localhost:3000/restful/info',{
        method: 'post',
        keepalive: true
      })
    }
    const sendBeacon = () => {
      navigator.sendBeacon('http://localhost:3000/restful/info')
    }
    const handleToB = (e) => {
      sendFetch()
      // sendBeacon()
    }
    a.addEventListener('click',handleToB)
  </script>

效果

image.png

效果和上面的sendBeacon是一样的

说一下他的优缺点

优点

  • 不需要额外处理数据,fetch怎么用就怎么用

缺点

  • 没想到啥缺点

ping

第三种,是a链接的属性ping

直接先看代码

<a id="a" href="./b.html" ping="http://localhost:3000/restful/info">TO b</a>

很简单,然后什么都不需要了,点击之后就会触发

image.png

image.png

从请求头可以看出来,他带了一个ping-to的头,表示跳转到哪里。

说一下他的优点

  • 非常简单,纯html,不用JavaScript
  • 请求头带了跳转信息,可以用来做埋点呀啥的,记录用户的点击

缺点

  • 用来做埋点的话,他又是需要post,不是常用的get
  • 携带的信息很少
  • 只能在a标签上使用,
  • 有些浏览器没有开启这个功能,firebox就没开

总结

  • 需要的信息极少,极致简单可以考虑用ping
  • 项目已经用fetch的,那使用fetch挺好的
  • 没有在用fetch的话,那用sendBeacon就挺好,只是需要使用post和处理下数据