前言
看到标题,其实各位前端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>
点击后,看下控制台效果
看起来成功了,没问题呀。but,让我们在控制台把网络改慢点
再重新点一次链接,看看效果
果不其然,之前能成功只是因为网速够快,在真实场景下,谁能保证客户的网络呢 φ(* ̄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>
效果图
我们可以看到,接口没有取消,状态是(未知)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>
效果
效果和上面的sendBeacon是一样的
说一下他的优缺点
优点
- 不需要额外处理数据,fetch怎么用就怎么用
缺点
- 没想到啥缺点
ping
第三种,是a链接的属性ping
直接先看代码
<a id="a" href="./b.html" ping="http://localhost:3000/restful/info">TO b</a>
很简单,然后什么都不需要了,点击之后就会触发
从请求头可以看出来,他带了一个ping-to的头,表示跳转到哪里。
说一下他的优点
- 非常简单,纯html,不用JavaScript
- 请求头带了跳转信息,可以用来做埋点呀啥的,记录用户的点击
缺点
- 用来做埋点的话,他又是需要post,不是常用的get
- 携带的信息很少
- 只能在a标签上使用,
- 有些浏览器没有开启这个功能,firebox就没开
总结
- 需要的信息极少,极致简单可以考虑用ping
- 项目已经用fetch的,那使用fetch挺好的
- 没有在用fetch的话,那用sendBeacon就挺好,只是需要使用post和处理下数据