改善同步 XMLHttpRequest() 中的網頁關閉問題

減少延遲導覽

Joe Medley
Joe Medley

網頁或應用程式在使用者關閉時,通常會有未提交的 Analytics 或其他資料。為避免資料遺失,部分網站會使用對 XMLHttpRequest() 的同步呼叫,在資料傳送至伺服器前,保持網頁或應用程式處於開啟狀態。除了有更好的方式來儲存資料,這項技巧還會延遲關閉網頁,最多延遲數秒,造成不好的使用者體驗。

這種做法需要改變,而瀏覽器也正在做出回應。XMLHttpRequest() 規格已淘汰並移除。Chrome 80 會採取第一步驟,禁止在多個事件處理常式中進行同步呼叫,特別是 beforeunloadunloadpagehidevisibilitychange,如果這些事件處理常式在關閉時觸發,WebKit 最近也推出了實作相同行為變更的提交內容

在本文中,我將簡要說明需要時間更新網站的使用者可用的選項,並概略說明 XMLHttpRequest() 的替代方案。

暫時選擇退出

Chrome 不想輕易關閉 XMLHttpRequest(),因此提供幾種暫時性的選擇退出選項。對於網際網路上的網站,可使用原始試用版。您可以利用這項功能,在網頁標頭中加入特定來源的符記,啟用同步 XMLHttpRequest() 呼叫。這個選項將於 2021 年 3 月某個時間的 Chrome 89 發布前結束。Chrome 企業版客戶也可以使用 AllowSyncXHRInPageDismissal 政策旗標,這項功能也會在同一時間結束。

替代方案

無論您如何將資料傳回伺服器,都最好避免等到頁面卸載後才一次傳送所有資料。除了造成不佳的使用者體驗之外,在現代瀏覽器上,卸載也無法保證可靠,而且如果發生錯誤,還可能導致資料遺失。具體來說,卸載事件通常不會在行動瀏覽器上觸發,因為在行動作業系統上,有許多關閉分頁或瀏覽器的方式,而不會觸發 unload 事件。在 XMLHttpRequest() 中,使用較小的酬載是一種選擇。這項要求現在已實施。根據規格要求,這兩種替代方案的上傳限制為每個情境 64 KB。

擷取保持運作

Fetch API 提供可靠的處理伺服器互動方式,以及一致的介面,可在不同平台 API 中使用。其中的選項之一是 keepalive,可確保要求持續進行,無論產生要求的網頁是否仍處於開啟狀態:

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

fetch() 方法的優點是可進一步控管傳送至伺服器的內容。在範例中沒有顯示的是,fetch() 也會傳回承諾,並以 Response 物件解析。由於我試圖避免頁面卸載,因此選擇不對其採取任何行動。

SendBeacon()

SendBeacon() 實際上會在幕後使用 Fetch API,因此會受到相同的 64 KB 酬載限制,並確保在頁面卸載後繼續要求。其主要優點是簡單易用。您可以使用一行程式碼提交資料:

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

結論

隨著各瀏覽器對 fetch() 的支援度提高,XMLHttpRequest() 或許會在某個時間點從網路平台中移除。瀏覽器供應商同意應移除這項功能,但這需要時間。停用最糟糕的用途之一,是改善所有使用者體驗的第一步。

相片來源:Matthew HamiltonUnsplash 網站上提供