前端資源加載失敗后的重試
.前端引用資源時出現了資源加載失敗(這里針對的是路徑引用異常或者url解析錯誤時)
解決這個問題首先要明確一下幾個步驟
1.什么情況或者什么時候重試
2.如何重試
3.重試過程中的邊界處理
這里引入里三個測試腳本,分別加載里三個不同的腳本其中1,3是正常輸出,2的內部輸出異常。但目前三個進本的加載時正常的
此時我們手動修改一個引用,讓其出現加載異常這里修改1的引用地址
這里控制臺目前捕獲到了兩種錯誤一種是引用地址引起的資源加載錯誤,一種是引用內部的錯誤;
前面我們提到過我們需要判斷什么時候重試
這里我們針對的是資源加載異常也就是引用地址問題引起的
所以我們需要在一開始就先進行錯誤類型的判斷。
因為我們瀏覽器加載的這些引用都屬于同步任務,順序進行的所以我們注冊的時間應該放大最開始的位置
此時我們發現并沒打印這個捕獲,這是因為‘error’這類事件是不會冒泡的,當然你在監聽這個窗口時就不會有捕獲,所以腳本加載出現了異常但是由于不能冒泡到捕獲內部所以無法得到監聽,這個時候我們就需要開啟冒泡,讓這個監聽發生在捕獲期間
由于監聽錯誤的事件針對的是整個窗口所有的錯誤當我們腳本內部,及引用都錯誤的時候這里會出現兩次打印
可以利用監聽事件內部提供的返回參數進行進一步處理
這里我們只處理類型是加載錯誤導致的,事件異常的我們不做處理,這樣我們就得到了一個基本的加載錯誤類型的獲取
借助返回參數內部的e.target
我們可以獲取到腳本類型錯誤目標進一步縮小范圍
重試的邏輯遵循上述前期獲取的類型約束進行
<script>//可重試的資源列表const dmmains=['1121212.com','122323411.com','localhost:8082']//創建一個重試的映射關系,用來檢測是重試過程失敗還是默認資源失敗const handleRetry={};window.addEventListener('error',(e)=>{if(e instanceof ErrorEvent || e.target.tagName!=='SCRIPT'){return}//獲取當前資源的路徑let basePath=e.target.src;//重新創建一個發送的url對象const urls=new URL(basePath);//根據獲取的url對象獲取基礎的路徑名稱建立對應關系const keys = urls.pathname//判斷當前的映射是否存在,用來記錄是否是第一重試if(!(keys in handleRetry)){handleRetry[keys] = 0}//用來記錄當前的映射地址的下標,方便在下次進行重試時重新進行地址切換const index = handleRetry[keys]//邊界處理判斷當前重試是否已經達到資源列表的最大值結束重試if(index>dmmains.length){return}const hosts= dmmains[index];//地址計數++ 進行下一步地址選取handleRetry[keys]++urls.host = hosts;//為了保證加載的順序依舊這里需要人為阻塞一下頁面加載線程,保證重試的腳本重試后加載順序依舊與原來一直,// 這里針對特定環境,如果引用沒有前后關系這里可以省略// document.write(`\<script src=${urls}><\/script>`) //特別注意該方式只針對特殊環境要求,因為會有性能問題,阻塞主線程加載console.log('當前重試的地址',hosts)//手動創建一個腳本元素,將當前重試地址替換進行重試const scripts=document.createElement('script');scripts.src = urls.toString()//將當前異常的腳本地址進行重試替換,將新重試的腳本放到異常腳本之前e.target.parentElement.insertBefore(scripts,e.target)//將重試結束的元素從頁面中清除e.target.remove()},true)</script>
根據我們的資源列表進行了兩次重試后正常加載了資源,但是我們發現結果返回的資源列表內打印的順序不對,1重試后到了最后,針對特殊資源加載的要求如果需要預先加載某些特定資源時我們需要調整該順序加載(但是資源加載的邏輯是同步的,我們需要人為阻塞線程讓重試資源進行優先重試加載)
使用原生的 document.write
進行阻塞,特別注意這里僅針對特殊要求下使用,該方式會阻塞線程造成性能問題