sendBeacon在数据上报方面对比img的优势是什么?

rt:关于sendBeacon描述如下:

navigator.sendBeacon() 方法可用于通过 HTTP POST 将少量数据异步传输到 Web 服务器。

根据以上描述,关键词为POST异步传输

  • 异步:就异步传输来熟,传统的ajax上报,以及常用的img上报都是异步,除非要同步在卸载文档这个时机去发。如果是用户行为事实上报的场景完全可以异步发送。
  • POST:与传统的img(get)上报相比,优势我理解可能出在数据传输长度上。由于url是发送给服务器的,所以不受浏览器导航栏处理长度限制,而关于服务器处理URI的长度,http1.1规定如下:

    HTTP协议不对URI的长度作事先的限制,服务器必须能够处理任何他们提供资源的URI,并且应该能够处理无限长度的URIs,这种无效长度的URL可能会在客户端以基于GET方式的请求时产生。如果服务器不能处理太长的URI的时候,服务器应该返回414状态码(此状态码代表Request-URI太长)。

也就是说只要日志服务器接受这个长度,完全是可以处理的。

然后根据我对img方案的理解,优势如下:
1、支持度高,不存在兼容性问题
2、onError可以处理发送失败的回调进行重试。

综上,我理解只有在监听用户卸载文档着一种场景下的日志上报,sendBeacon有异步优势,此外都是img的应用性要更加广泛一点。

想请教各位大佬什么场景下时必须在卸载文档这个时机去发送的,我目前接触到的场景时退出挽留,但既然已经退出挽留了,img发送也不会造成文档卸载延迟的问题了。还是sendBeacon有什么其他的优势?

阅读 3.8k
3 个回答

时隔一个月我对这个问题有了新的理解,所以也来答一下
希望对同样关注这个问题的人有所帮助:)

在我提出这个问题的时候其实我纠结的是sendBeacon在卸载场景发送数据的必要性
我当时认为如果没有这个必要性,则完全没必要用它取代兼容性更好的new Image方案

事实上我这段时机专注研究性能相关内容,
我注意到在很多场景下卸载时使用sendBeacon是十分必要的

1、为什么在卸载时发送日志?
举个例子来说,在前端性能指标里有一个LCP,统计最大内容绘制,统计最大内容绘制的时间

要知道对于长页面在整个用户访问过程中,最大内容是不断变化的,每变化一次就上报一次显然是不合理的。像这种持续变化的统计内容,只有在用户离开页面时进行上报才最具统计意义。

2、为什么SendBeacon可以解决这个问题?
传统的日志上报有两种分别是Image发送和异步请求发送。但在卸载场景下这两种都有问题

  • 异步请求的ajax会在卸载时被忽略
  • new Image则会推迟文档卸载

而sendBeacon作为一种单向数据请求则是专门解决这个问题的,同时具备以下特点:

  • 信标请求被优先处理以避免与时间关键操作和更高优先级的网络请求竞争。
  • 用户代理可以有效地合并信标请求,以优化移动设备上的能源使用。
  • 信标请求保证在页面卸载之前启动,并且允许运行完成,而不需要阻塞请求或其他阻止用户交互事件处理的技术。

补充:
监听卸载时机(unload)来发送日志是不合理的,有以下两点理由:
1、unload并非是一个稳定触发的事件
2、unload与浏览器关键优化BFCache有冲突关系,可参考以下内容:

以下情况浏览器(Firefox)不缓存页面。下面是一些页面不被缓存的常见的编程的原因:

  • 页面使用 unload 或者 beforeunload 处理程序;
  • 页面设置 "cache-control: no-store".
  • 页面是 HTTPS 同时页面至少有一个以下设置:
  • "Cache-Control: no-cache"
  • "Pragma: no-cache"
  • 使用 "Expires: 0" 或者 "Expires" 设置相对于“Date”header 值的过去日期值 (除非指定 "Cache-Control: max-age=");
  • 当用户导航跳离页面时页面还没有完全加载或者因为其他原因有等待(pending)的网络请求 (例如 XMLHttpRequest));
  • 页面运行 IndexedDB 事件;
  • 顶级页面包含 frames (例如 <iframe>) 因为这里列出的任何原因 而没有被缓存;
  • 页面是在 frame 内而且用户在这个框架中加载一个新页面(在这种情况下,当用户离开这个页面,最后加载入 frames 的内容会被缓存)。

针对unload可能出现的问题,更佳的方案是监听pagehide事件与visibilitychange

  • 如果某些浏览器在实现上无法保证图片的载入,就会导致上报数据的丢失
  • 单纯的调用 sendBeacon 可能比处理图片代码还是要少些

没用过,所以仅供参考

  • img 会阻塞页面的 onload。
  • onunload/onbeforunload 时你没法保证 ajax 或 img 在发送结束前不被销毁掉(尤其弱网环境)。漏斗模型里“跳出”行为也是个很重要的指标,你不能说那就不采集了吧。

MDN 里的对此方法的描述就已经告诉你了为啥需要有这么个方法:

image.png

https://developer.mozilla.org...

实际上没有只采用某一种方案的,主流都是几种方式混用以满足最大兼容性。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题