by @zhangbao(zhangbao) #0114
原文链接:Improving page dismissal in synchronous XMLHttpRequest(), by Joe Medley
引言
使用 XMLHttpRequest
发送同步请求的方式已经计划从规范中删除,不再建议开发者使用。我们可以使用 navigator.sendBeacon()
方法替代。
// ❌ No...
window.addEventListener("unload", function logData() {
var xhr = new XMLHttpRequest();
xhr.open("POST", "/log", false); // third parameter of `false` means synchronous
xhr.send(analyticsData);
});
// ✅ Yes!
window.addEventListener("unload", function logData() {
navigator.sendBeacon("/log", analyticsData);
});
正文
在用户将页面完全关闭前,有时需要向后台传输一些必要数据(比如:用户行为分析数据)。为了避免数据丢失,一些网站会使用同步的 XMLHttpRequest()
请求,直到数据完全传递到服务器,再关闭页面。这种处理方式,可能会导致诸如页面延迟几秒后再关闭的糟糕体验,其实我们有更好的解决这类问题的方式。
XMLHttpRequest 规范提到 同步 XMLHttpRequest 已经计划从 Web 平台删除,开发者禁止将 new XMLHttpRequest().open(method, url [, async = true [, username = null [, password = null]]])
方法中 async
参数赋值为 false
使用。Chrome 80 中迈出了第一步,开始禁止在如下这些事件处理器中使用同步 XMLHttpRequest:beforeunload
、unload
、pagehide
、visibilitychange
。Webkit 最近也有一个实现此行为的提交。
规范中禁止开发者使用同步 XMLHttpRequest 的说明
本文中,我们将从两个方面简要描述如果应对这次 API 改变:
- 那么需要时间更新站点代码的开发者可以如何做?
- 同步 XMLHttpRequest 的替代方案有哪些?
临时 opt-out
Chrome 并未简单粗暴的直接关闭了对同步 XMLHttpRequest 的支持,它还给我们提供一些可供使用的 opt-outs。对英特网上的网页,我们可以使用一个 Origin Trial。注册完成后,会在页面的请求头中添加特定于 Origin 的 Token(origin-specific token) 来标识并启用同步 XMLHttpRequest 功能。这个支持会在 Chrome 86 发布前不久结束,时间大约在 2020 年 10 月下旬。
同步 XMLHttpRequest 的 Trial 支持会在 2020 年 10 月 21 日结束
可选方案
除非逼不得已,不要等到页面卸载的时候再发送数据给服务器。除了造成糟糕的用户体验之外,如果出现问题,还会有丢失数据的风险。卸载事件通常不会在移动端浏览器中触发,这是因为在移动设备中,有很多种在不引起触 unload
事件的情况下,退出页面或浏览器的方式。发送 XMLHttpRequest 的时候,我们可以选择使用少量请求数据(small payloads)的办法。现在,这是一个必要条件。根据规范要求,下面两种替代方案的上传数据的限制都是都是 64 KB。
Fetch keepalive
Fetch API 提供了一套健壮的与服务器端交互的方式,提供了跨越不同平台 API 的一致接口。它提供了一个选项 keepalive
,保证不管发送请求的页面关闭与否,请求都会持续直到结束。
window.addEventListener('unload', {
fetch('/siteAnalytics', {
method: 'POST',
body: getStatistics(),
keepalive: true
});
}
fetch()
方法的优点是可以更好地控制发送到服务器的内容。fetch()
方法会返回一个 Promise 对象,resolve 值是 Response
对象。 本例中,我没有使用 fetch()
返回值做任何其他的事情,是因为这个请求发生在页面卸载之时,因此并不一定会保证执行。
SendBeacon()
SendBeacon()
方法底层的使用的是 Fetch API。这样就能明白为什么它也有 64 KB 的上传数据限制,也能明白为什么它还能在页面卸载后继续请求。它的主要优点是简单,只要用一行代码就能搞定。
window.addEventListener('unload', {
navigator.sendBeacon('/siteAnalytics', getStatistics());
}
总结
随着 Fetch API 在各浏览器开始广泛支持,XMLHttpRequest 有望在未来的某个时候从 Web 平台上移除。浏览器厂商都同意应该删除它,但这需要些时间。摒弃其中一个最糟糕的用例(也就说本文中介绍的——同步 XMLHttpRequest)是改善每个用户美好体验的第一步。
(正文完)
广告时间(长期有效)
我有一位好朋友开了一间猫舍,在此帮她宣传一下。现在猫舍里养的都是布偶猫。如果你也是个猫奴并且有需要的话,不妨扫一扫她的【闲鱼】二维码。不买也不要紧,看看也行。
(完)