在前端應用越來複雜的今天,為了監控前端應用是否正常執行,通常會在前端收集一些錯誤與效能等資料,最終我們會將這些資料上報到服務端。
上報的方式有很多,理論上我們只要能把資料發給服務端就行了。在瀏覽器中可以傳送請求的方式非常多,包括不限於:xhr
、fetch
、script
標籤、img
標籤、link
標籤、CSS背景圖等。
不同的上報方式之間存在很大的差異。目前主流的上報方式是利用img
標籤的src
屬性傳送請求,例如:
(new Image).src = `/haopv.gif?a=xx&b=xxx`
複製程式碼
因為日誌上報不需要響應處理,只需要把資料發過去就行。並且大部分接收日誌的伺服器地址與業務方可能不是一個部門,甚至可能不是一個公司,所以會涉及到跨域問題。使用img
標籤的src
屬性既可以把資料傳送給服務端又不需要接收響應,同時解決了跨域問題,所以是目前比較受歡迎的日誌上報實現方式。
但是這樣就真的沒問題了麼?
日誌上報並不是應用的主要功能邏輯,也就是說,日誌上報是低優先順序的,它不應該與其他高優先順序操作(例如:獲取關鍵資源、輸入響應、執行動畫等)去競爭網路與計算資源(通俗的說就是日誌上報行為不應該影響業務邏輯,不應該佔用業務計算資源)。但是這種單向請求又負責傳遞應用的錯誤與效能資料,所以我們必須要確保它會被交付到服務端。
通常,為了提高交付率,我們會選擇立即交付每個收集到的資料,而不是合併與推遲交付。延遲傳遞可能意味著請求沒有足夠的時間來成功完成,這可能導致重要的應用資料丟失。
這就意味著我們的交付行為有可能會被插入到正在忙碌工作的事件迴圈中,從而搶佔了其他高優先順序的任務的資源,因為JS是單執行緒的。這有可能會損害使用者體驗。
我們如何確保日誌資料會被交付的同時,儘可能地減少與其他關鍵操作的資源爭用呢?答案是信標(Beacon)。
信標(Beacon)
信標(Beacon)可以非同步與非阻塞的資料傳輸,從而最大限度地減少與其他關鍵操作的資源爭用,同時它可以確保這些請求一定會被處理並將其傳遞到服務端:
- 信標請求優先避免與關鍵操作和更高優先順序的網路請求競爭。
- 信標請求可以有效地合併,以優化移動裝置上的能量使用。
- 保證頁面解除安裝之前啟動信標請求,並允許執行完成且不會阻塞請求或阻塞處理使用者互動事件的任務。
信標的使用非常簡單:
var data = JSON.stringify({
name: 'Berwin'
});
navigator.sendBeacon('/haopv', data)
複製程式碼
引數
- url:上報的目標地址
- data:被上報的資料
- 返回值(Return Value):sendBeacon方法被執行後返回一個布林值,
true
代表使用者代理成功地將信標請求加入到佇列中,否則返回false
。
使用者代理對通過信標傳送的資料量進行限制,以確保請求被成功傳遞到服務端,並且對瀏覽器活動的影響降到最小。如果要排隊的資料量超出了使用者代理的限制,sendBeacon方法將返回
false
,返回true
代表瀏覽器已將資料排隊等待傳遞。然而,由於實際資料傳輸是非同步的,所以此方法不提供任何關於資料傳輸是否成功的資訊。
雖然信標得到了很高的支援度,但還是無法在所有瀏覽器中使用,所以如果您想使用信標上報前端日誌,一些特徵檢測是必要的。
還有一個需要注意的是,通過信標傳送的請求,請求方法均為POST
,且不支援修改。
總結
日誌上報在生產環境下不僅僅是把請求發出去。日誌上報並不是主要邏輯所以優先順序很低,為了最佳的使用者體驗,在考慮避免佔用業務計算資源和避免競爭業務網路請求的同時我們還要保證資料一定會交付到服務端,最好的方式是儘可能的使用信標(Beacon)。