改进同步 XMLHttpRequest() 中的页面关闭

减少延迟导航

Joe Medley
Joe Medley

在用户关闭网页或应用时,网页或应用通常会有未提交的 Google Analytics 数据或其他数据。为防止数据丢失,某些网站会使用对 XMLHttpRequest() 的同步调用来保持网页或应用处于打开状态,直到其数据传递到服务器。不仅有更好的数据保存方法,而且此方法会将页面关闭延迟长达几秒钟,从而给用户带来糟糕的体验。

这种做法需要改变,浏览器也在做出回应。XMLHttpRequest() 规范已列入弃用和移除计划。Chrome 80 迈出了第一步,禁止在多个事件处理脚本(特别是 beforeunloadunloadpagehidevisibilitychange)在关闭时触发时进行同步调用。WebKit 最近还发布了实现了相同行为更改的提交

在本文中,我将简要介绍适用于需要时间更新网站的用户的选项,并概述 XMLHttpRequest() 的替代方案。

Chrome 不想轻易停用 XMLHttpRequest(),因此提供了一些临时停用选项。对于互联网上的网站,可以使用源代码试用版。这样,您就可以向页面标头添加特定于来源的令牌,以启用同步 XMLHttpRequest() 调用。此选项将于 Chrome 89 发布前不久(2021 年 3 月的某个时间)停用。Chrome 企业版客户还可以使用 AllowSyncXHRInPageDismissal 政策标志,该标志将于同一时间结束。

替代方案

无论您以何种方式将数据发送回服务器,最好避免等到页面卸载后再一次性发送所有数据。除了会造成糟糕的用户体验之外,在现代浏览器上卸载不可靠,如果出现问题,可能会导致数据丢失。具体而言,移动浏览器上通常不会触发卸载事件,因为在移动操作系统上,有许多方法可以关闭标签页或浏览器,而无需触发 unload 事件。XMLHttpRequest() 中,使用小型载荷是一种选择。现在,这已成为一项要求。这两种替代方案的每个上下文的上传限制均为 64 KB,如规范所要求。

Fetch keepalive

Fetch API 提供了一种处理服务器互动的强大方法,以及可在不同平台 API 中使用的一致接口。其中一个选项是 keepalive,它可确保无论发出请求的网页是否保持打开状态,请求都会继续:

window.addEventListener('unload', {
  fetch
('/siteAnalytics', {
    method
: 'POST',
    body
: getStatistics(),
    keepalive
: true
 
});
}

fetch() 方法的优势在于,您可以更好地控制发送到服务器的内容。我没有在示例中展示的是,fetch() 还会返回一个 promise,该 promise 会通过 Response 对象解析。由于我正尝试避免干扰页面卸载,因此选择不对其执行任何操作。

SendBeacon()

SendBeacon() 实际上在后台使用 Fetch API,因此它也存在 64 KB 的载荷限制,并且还会确保请求在页面卸载后继续。其主要优势在于简单。借助它,您只需一行代码即可提交数据:

window.addEventListener('unload', {
  navigator
.sendBeacon('/siteAnalytics', getStatistics());
}

总结

随着 fetch() 在各浏览器中的使用越来越广泛,我们希望能够在某个时间点从网络平台中移除 XMLHttpRequest()。浏览器供应商同意应将其移除,但这需要一些时间。弃用其中最糟糕的用例是改善所有用户体验的第一步。

照片由 Matthew Hamilton 拍摄,选自 Unsplash