改进同步 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