问题描述
现在假设有一个script资源加载失败,代码如下
<!DOCTYPE html>
<html>
<head>
<title>script 资源加载失败</title>
</head>
<body>
<script src="http:hdh.sdas.asdas/1.js"></script>
</body>
</html>
我们希望在加载失败的时候进行一系列的解决操作,那么就需要有两步操作:
- 捕获加载失败事件
- 对加载失败操作进行处理(重新获取重试)
捕获加载失败事件
注意:
这里既然是捕获script
资源加载错误,就要在script
资源加载之前注册监听事件。因此把这段代码放在所有script
标签之前
全局监听错误事件
true
: 是一个可选的参数,表示在捕获阶段触发事件处理程序。在事件传播过程中,捕获阶段是指从最外层的元素向目标元素的阶段。这里设置为true表示在捕获阶段触发处理程序,如果设置为false或省略,则在冒泡阶段触发处理程序(从目标元素向最外层的元素)。
<!DOCTYPE html>
<!DOCTYPE html>
<html>
<head>
<title>script 资源加载失败</title>
<script type="text/javascript">
<!-- 这里需要添加 true 属性 -->
window.addEventListener('error',(e)=>{
console.log('有错误')
},true)
</script>
</head>
<body>
<script src="http:hdh.sdas.asdas/1.js"></script>
</body>
</html>
捕获资源加载失败类型错误
首先我们打印一下监听事件的 e
元素,会发现 script 加载失败事件的属性和别的错误属性有两个特征,只要把握住这两个特征就可以进行判断处理:
- 特点1:是个
Event
对象 - 特点2:
target
属性为script
<!DOCTYPE html>
<html>
<head>
<title>script 资源加载失败</title>
<script type="text/javascript">
<!-- 这里需要添加 true 属性 -->
window.addEventListener('error',(e)=>{
const tag = e.target
// 添加判断事件类型
if(tag.tagName === 'SCRIPT' && !(e instanceof ErrorEvent)){
console.log('有错误')
}
},true)
</script>
</head>
<body>
<script src="http:hdh.sdas.asdas/1.js"></script>
</body>
</html>
完整案例代码
<!DOCTYPE html>
<html>
<head>
<title>script 资源加载失败</title>
<script type="text/javascript">
// 这里是模拟的一些备用域名
const domains = [
'test.1.com',
'test.2.com',
'test.3.com'
]
// 最大的重试次数
const maxRetry = 5
// 资源加载信息
const retryInfo = {}
window.addEventListener('error',(e)=>{
console.log('e',e)
const tag = e.target
// 只对 script 加载失败错误进行处理
if(tag.tagName === 'SCRIPT' && !(e instanceof ErrorEvent)){
const url = new URL(tag.src)
console.log('url',url)
// 如果该文件没有加载失败信息,则初始化
if(!retryInfo[url.pathname]){
retryInfo[url.pathname] = {
times:0,
nextIndex:0
}
}
const info = retryInfo[url.pathname]
console.log('info',retryInfo)
// 加载失败次数小于最大重试次数
if(info.times < maxRetry){
url.host = domains[info.nextIndex]
// 阻塞页面后续的加载
document.write(`<script src="${url.toString()}">\<\/script>`)
// 以下这种方式就不会按顺序加载 script 内容
// const script = document.createElement('script')
// script.src = url.toString()
// document.body.insertBefore(script,tag)
// 下标循环
info.nextIndex = (info.nextIndex + 1) % domains.length
info.times++
}
}
},true)
</script>
</head>
<body>
<!-- 模拟一个加载失败的资源 -->
<script src="http:hdh.sdas.asdas/1.js"></script>
</body>
</html>