TAT.joeyguo 前端資源加載失敗優化
In 未分類 on 2021年01月07日 by view: 10,307
0

原文地址

Web 項目上線后,開始開門迎客,等待著來自大江南北、有著各式各樣網絡狀態的用戶蒞臨。在千差萬別的網絡狀態中,訪問頁面難免會遇到前端資源加載失敗的情況,占比或許不高,但一遇到,輕則頁面樣式錯亂,重則白屏打不開,影響用戶體驗感受,緊急情況下甚至影響了用戶的工作,屬于非常嚴重的問題。本文將從如何監控加載失敗、加載失敗如何優化、始終加載失敗又該如何處理等問題逐一分析。

如何監控資源加載失敗

方案一:script onerror

我們可以給 script 標簽添加上 onerror 屬性,這樣在加載失敗時觸發事件回調,從而捕捉到異常。

并且,借助構建工具 ( 如 webpack 的 script-ext-html-webpack-plugin 插件) ,我們可以輕易地完成對所有 script 標簽自動化注入 onerror 標簽屬性,不費吹灰之力。

方案二:window.addEventListener

上述方案已然不錯,但我們也試想是否可以減少 onerrror 標簽大量注入呢?類比腳本錯誤 onerror 的全局監控方式(詳見:腳本錯誤量極致優化-監控上報與 Script error),是否也可以通過 window.onerror 去全局監聽加載失敗呢?

答案否定的,因為 onerror 的事件并不會向上冒泡,window.onerror 接收不到加載失敗的錯誤。冒泡雖不行,但捕獲可以!我們可以通過捕獲的方式全局監控加載失敗的錯誤,雖然這也監控到了腳本錯誤,但通過 !(event instanceof ErrorEvent) 判斷便可以篩選出加載失敗的錯誤。

通過監控數據分析,我們發現現實情況不容樂觀。訪問頁面時存在資源加載失敗的情況超過了 10000 例/天,且隨著頁面訪問量的上升而增加。

另外,監控資源加載失敗的方式不止這些,上述兩種方式都屬于較好的方案,其他的方式就不再展開。

優化資源加載失敗

方案一:加載失敗時,刷新頁面 (reload)

有了監控數據后,便可著手優化。當資源加載失敗時,刷新頁面可能是最簡單直接的嘗試恢復方式。于是當監控到資源加載失敗時,我們通過 location.reload(true) 強制瀏覽器刷新重新加載資源,并且為了防止出現一直刷新的情況,結合了 SessionStorage 限制自動刷新次數。

103794043-337f9500-507f-11eb-970d-a984e61252ad

通過監控數據發現,通過自動刷新頁面,最終能恢復正常加載占異??偭?30%,優化比例不高,且刷新頁面導致了出現多次的頁面全白,用戶體驗不好。

方案二:針對加載失敗的文件進行重加載

替換域名動態重加載

只對加載失敗的文件進行重加載。并且,為了防止域名劫持等導致加載失敗的原因,對加載失敗文件采用替換域名的方式進行重加載。替換域名的方式可以采用重試多個 cdn 域名,并最終重試到頁面主域名的靜態服務器上(主域名被劫持的可能性?。?/p>

103795733-4e530900-5081-11eb-8e70-033ba7b492a6

然而,失敗資源重加載成功后,頁面原有的加載順序可能發生變化,最終執行順序發現變化也將導致執行異常。

103796632-6e36fc80-5082-11eb-86a4-c6cbf8d1b2ec

保證 JS 按順序執行

在不需要考慮兼容性的情況下,資源加載失敗時通過 document.write 寫入新的 script 標簽,可以阻塞后續 script 腳本的執行,直到新標簽加載并執行完畢,從而保證原來的順序。但它在 IE、Edge 卻無法正常工作,滿足不了我們項目的兼容性。

于是我們需要增加 “管理 JS 執行順序” 的邏輯。使 JS 文件加載完成后,先檢查所依賴的文件是否都加載完成,再執行業務邏輯。當存在加載失敗時,則會等待文件加載完成后再執行,從而保證正常執行。

103797758-d5a17c00-5083-11eb-9b47-05fee718bf8d

手動管理模塊文件之間的依賴和執行時機存在著較大的維護成本。而實際上現代的模塊打包工具,如 webpack ,已經天然的處理好這個問題。通過分析構建后的代碼可以發現,構建生成的代碼不僅支持模塊間的依賴管理,也支持了上述的等待加載完成后再統一執行的邏輯。

103799361-f4a10d80-5085-11eb-81a2-5209ed0a0fdd

然而,在默認情況下,業務代碼的執行不會判斷配置的 external 模塊是否存在。所以當 external 文件未加載完成或加載失敗時,使用對應模塊將會導致報錯。

所以我們需要在業務邏輯執行前,保證所依賴的 external 都加載完成。最終通過開發 wait-external-webpack-plugin webpack 插件,在構建時分析所依賴的 external,并注入監控代碼,等待所有依賴的文件都加載完成后再統一順序執行。(詳見:Webpack 打包后代碼執行時機分析與優化

至此,針對加載失敗資源重試的邏輯最終都通過構建工具自動完成,對開發者透明。重試后存在加載失敗的情況優化了 99%。減少了大部分原先加載失敗導致異常的情況。

始終加載失敗該怎么辦

用戶網絡千變萬化,或臨時斷網、或瀏覽器突然異常,那些始終加載失敗的情況,我們又該如何應對呢?
一個友好的提醒彈框或是最后的稻草,避免用戶的無效等待,緩解用戶感受。

103801420-ae00e280-5088-11eb-9e9d-ebcadad9ced5

總結

以上,便是對資源加載失敗優化的整體方案,從如何監控加載失敗、加載失敗時重試、重試失敗后的提醒等方面。大幅優化修正了加載失敗的問題,也緩解著實遇到異常的用戶使用體驗。

如有不妥,懇請斧正,謝謝。

查看更多文章 >>
https://github.com/joeyguo/blog

原創文章轉載請注明:

轉載自AlloyTeam:http://www.ecomenagepro.com/2021/01/15358/

發表評論