js腳本加載失敗問題解決辦法
當(dāng)我們?cè)谶\(yùn)行某一個(gè)項(xiàng)目時(shí),它的某些JavaScript腳本可能加載不出來,報(bào)錯(cuò)。 像現(xiàn)在單頁界面應(yīng)用基本上都是通過js來構(gòu)建,一旦加載不出,這個(gè)項(xiàng)目就不能運(yùn)行了,那怎么辦?我們?nèi)绾谓鉀Q這個(gè)問題?

這里采用的方案是,重新加載JavaScript腳本。那么什么時(shí)候去重新加載js,如何重新加載js?在js腳本加載不出來時(shí),就需要去重試加載。那我們?cè)趺粗纉s有沒有加載失敗,我們可以在<script src="https://cdn.topskys.org/v0/loadjs.js"></script>標(biāo)簽上添加一個(gè)監(jiān)聽加載失敗的事件 οnerrοr="console.log('error')",當(dāng)出現(xiàn)錯(cuò)誤會(huì)觸發(fā)onerror事件。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script onerror="console.log('error')" src="https://cdn.topskys.org/v0/loadjs.js"></script>
</body>
</html>
可以看到,當(dāng)加載js出現(xiàn)錯(cuò)誤時(shí),onerror監(jiān)聽到了錯(cuò)誤。但是在工程化的環(huán)境,這些<script></script>標(biāo)簽元素都是自動(dòng)生成的,給這些標(biāo)簽添加上onerror事件,這種方式又特別麻煩。我們可以給整個(gè)window添加error監(jiān)聽事件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="https://cdn.topskys.org/v0/loadjs.js"></script>
<script>
window.addEventListener("error",e=>{
console.log("error loading")
});
</script>
</body>
</html>但上一個(gè)js腳本加載出現(xiàn)錯(cuò)誤,window監(jiān)聽error事件還有沒有注冊(cè),所以說我們需要把它寫在最前邊,放到<head></head>里,一開始就去監(jiān)聽。當(dāng)然,寫到最前邊它也不會(huì)觸發(fā),因?yàn)樗粫?huì)事件冒泡,只能在捕獲階段就拿到該事件,在監(jiān)聽事件函數(shù)后加“, true”:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
window.addEventListener("error", e => {
console.log("error loading")
},true); // 捕獲階段拿到事件
</script>
</head>
<body>
<script src="https://cdn.topskys.org/v0/loadjs.js"></script>
</body>
</html>
觸發(fā)error的事件類型也很多,如圖片加載錯(cuò)誤、在js中throw 1報(bào)錯(cuò)也會(huì)觸發(fā)error。我么怎么樣縮小觸發(fā)error的范圍,只監(jiān)聽到那些<script src=""></script> 加載js不出來的情況?我們發(fā)現(xiàn)error事件中,參數(shù)e輸入的target是script元素:

但是呢,throw 在error事件里報(bào)的是ErrorEvent錯(cuò)誤,里面包含各種屬性,故我們可以準(zhǔn)確地找到某一種錯(cuò)誤。
<script>
throw 1;
</script>
我們需要在window監(jiān)聽error事件里面作一個(gè)判斷:
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
window.addEventListener("error", e => {
const tag=e.target
if(tag.tagName==='SCRIPT' && !(e instanceof ErrorEvent)) {
console.log("JS 加載錯(cuò)誤")
}
},true);
</script>
</head>到這里頁面解決了,什么時(shí)候去重新加載js的問題,還剩下如何重試加載js。
首先,我們需要引入多個(gè)新地址的script標(biāo)簽加載js,當(dāng)某一個(gè)js加載失敗時(shí),就會(huì)被觸發(fā)window監(jiān)聽事件error,執(zhí)行重試更換域名生成新的script標(biāo)簽加載js,需要靠document.write()才能阻塞后面的js加載,不阻塞后續(xù)js加載,會(huì)造成js加載順序混亂。
注意,在使用document.write()寫入script標(biāo)簽時(shí),需要對(duì)標(biāo)簽結(jié)束符進(jìn)行轉(zhuǎn)譯,否則會(huì)被認(rèn)為是上個(gè)標(biāo)簽的結(jié)束符。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
const domains = ["https://cdn.topskys.org/v0", "https://cdn.topskys1.org/v1", "https://cdn.topskys2.org/v2"]; // 重試域名數(shù)組
const maxRetry=3; // 最多重試次數(shù)
const retryInfo={}; // 記錄重試次數(shù)及下一個(gè)重試的域名數(shù)組下標(biāo){times:1,nextIndex:2}
window.addEventListener("error", e => {
const tag = e.target
if (tag.tagName === 'SCRIPT' && !(e instanceof ErrorEvent)) {
// console.log("JS 加載錯(cuò)誤")
const url=new URL(tag.src) // 拿到script標(biāo)簽的src域名
if(!retryInfo[url.pathname]){
retryInfo[url.pathname]={
times:0,
nextIndex:0,
}
}
const info=retryInfo[url.pathname]; // 取出文件路徑 ./loadjs.js ./js.js ./y.js
const script=document.createElement("script")
url.host=domains[info.nextIndex]; // 更換域名
document.write(`<script src="${url.toString()}">\<\/script>`); // 新加載script元素,需要阻塞后面的script加載js,否則加載js順序會(huì)亂。注意轉(zhuǎn)譯</script>,否則會(huì)被認(rèn)為上面的script結(jié)束標(biāo)簽。
script.src=url.toString();
document.body.insertBefore(script,tag); // 將新的script標(biāo)簽插入加載錯(cuò)誤標(biāo)簽前
// 修改重試信息
info.times++;
info.nextIndex=(info.nextIndex+1)%domains.length;
}
}, true);
</script>
</head>
<body>
<script src="https://cdn.topskys.org/v0/js.js"></script>
<script src="https://cdn.xx1.cn/y.js"></script>
<script src="https://cdn.xx2.com/loadjs.js"></script>
</body>
</html>那么,如何解決js加載失敗的問題就解決了。但如果script標(biāo)簽上有defer、async及工程化項(xiàng)目中呢,有如何該解決?
總結(jié)
到此這篇關(guān)于js腳本加載失敗問題解決辦法的文章就介紹到這了,更多相關(guān)js腳本加載失敗內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript中的console.trace()函數(shù)介紹
這篇文章主要介紹了JavaScript中的console.trace()函數(shù)詳細(xì)介紹,console.trace()函數(shù)用來打印函數(shù)調(diào)用的棧信息,需要的朋友可以參考下2014-12-12
uniapp微信小程序授權(quán)登錄并獲取手機(jī)號(hào)的方法
這篇文章主要給大家介紹了關(guān)于uniapp微信小程序授權(quán)登錄并獲取手機(jī)號(hào)的相關(guān)資料,我們?cè)趗niapp開發(fā)微信小程序的過程中,經(jīng)常需要在微信端登錄,需要的朋友可以參考下2023-06-06
僅img元素創(chuàng)建后不添加到文檔中會(huì)執(zhí)行onload事件的解決方法
僅img元素創(chuàng)建后不添加到文檔中會(huì)執(zhí)行onload事件的解決方法,需要的朋友可以參考下。2011-07-07
簡(jiǎn)單談?wù)刯avascript代碼復(fù)用模式
這篇文章主要簡(jiǎn)單談?wù)刯avascript代碼復(fù)用模式,主要詳細(xì)介紹了類式繼承模式中的默認(rèn)模式,希望大家能夠喜歡。2015-01-01
JS對(duì)話框_JS模態(tài)對(duì)話框showModalDialog用法總結(jié)
本篇文章主要是對(duì)JS對(duì)話框_JS模態(tài)對(duì)話框showModalDialog的用法進(jìn)行了總結(jié)介紹,需要的朋友可以過來參考下,希望對(duì)大家有所幫助2014-01-01
JavaScript實(shí)現(xiàn)的內(nèi)存數(shù)據(jù)庫LokiJS介紹和入門實(shí)例
這篇文章主要介紹了JavaScript實(shí)現(xiàn)的內(nèi)存數(shù)據(jù)庫LokiJS介紹和入門實(shí)例,LokiJS是一個(gè)內(nèi)存數(shù)據(jù)庫,將性能考慮放在第一位,使用JavaScript編寫,需要的朋友可以參考下2014-11-11
通過JS解決頁面刷新導(dǎo)致按鈕OnClientClick事件消失問題
這篇文章主要介紹了如何通過JS解決頁面刷新導(dǎo)致按鈕OnClientClick事件消失問題,OnClientClick 提供客戶端JS執(zhí)行能力,并以 return false 或 return true 來決定是否繼續(xù)執(zhí)行 OnClick 事件,需要的朋友可以參考下2024-12-12

