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

減少延遲導覽

Joe Medley
Joe Medley

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

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

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

Chrome 不想輕易關閉 XMLHttpRequest(),因此提供幾種暫時性的選擇退出選項。對於網際網路上的網站,可使用原始試用版。您可以利用這項功能,在網頁標頭中加入特定來源的符記,啟用同步 XMLHttpRequest() 呼叫。這個選項將於 Chrome 89 推出前不久 (2021 年 3 月某個時間) 終止。Enterprise 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 Hamilton 發表於 Unsplash 網站上