<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
const backupDomains = ["123.cn", "456.com", "789.net"];
const nextDomain = {};
window.addEventListener("error", e => {
console.log(e);
if(e instanceof ErrorEvent || e.target.tagName !== "SCRIPT") {
return;
}
const url = new URL(e.target.src);
const pathname = url.pathname;
if(!nextDomain[pathname]) {
nextDomain[pathname] = 0;
}
const index = nextDomain[pathname];
if(index >= backupDomains.length) {
return;
}
const domain = backupDomains[index];
url.hostname = domain;
const newUrl = url.toString();
document.write(`\<script src="${newUrl}">\<\/script>`);
nextDomain[pathname]++;
}, true);
</script>
</head>
一检激、script 標簽特性
① script 標簽?zāi)J是同步加載的齐莲。當 HTML 頁面在加載的過程中嚣鄙,遇到了一個 script 標簽放祟,就會中斷 HTML 頁面的加載鳍怨,然后根據(jù)對應(yīng)的 src 地址向服務(wù)器發(fā)起請求,當對應(yīng)的 javascript 腳本加載完成后跪妥,HTML 頁面仍然不能加載鞋喇,還必須等加載的 javascript 腳本執(zhí)行完成后,HTML 頁面才能繼續(xù)往下加載眉撵。
② 當遇到 script 標簽的時候會立即渲染一次侦香。當 HTML 頁面加載的過程中落塑,遇到了一個 script 標簽,如果之前已經(jīng)加載了部分 HTML 內(nèi)容罐韩,那么會先將之前加載的 HTML 內(nèi)容渲染出來憾赁,然后再去加載對應(yīng)的 javascript 腳本。
二散吵、script 標簽優(yōu)化
script 標簽?zāi)J是同步加載的龙考,但是其提供了一些屬性可以變成異步加載,如: async矾睦、defer晦款、type="module"
① async: 異步加載對應(yīng)的 javascript 腳本,不阻塞 HTML 頁面的渲染枚冗,當對應(yīng)的 javascript 加載完成后柬赐,如果此時 HTML 頁面還未加載完成,那么會阻塞頁面的渲染官紫,等 javascript 執(zhí)行完成后再繼續(xù) HTML 頁面的加載肛宋。
② defer: 異步加載對應(yīng)的 javascript 腳本,不阻塞 HTML 頁面的渲染束世,當對應(yīng)的 javascript 加載完成后酝陈,如果此時 HTML 頁面還未加載完成,那么不會阻塞頁面的渲染毁涉,等 HTML 頁面加載完成后再接著執(zhí)行加載完成的 javascript 腳本沉帮。
③ type="module": 也是能起到異步加載的效果,效果同 defer贫堰,不過其可以配合 async 屬性讓 javascript 加載完成后立即執(zhí)行穆壕。