<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>demo</title>
</head>
<body>
<script>
const handError = (srcEle, num = 1) => {
console.log(srcEle.src, ' is error');
const url = new URL(srcEle.src);
const newUrl = 'test' + srcEle.src.split('/').pop();
const newSrciptStr = `<script src=${newUrl} onerror="handError(this)" onload="handLoad(this)"><\/script>`;
document.write(newSrciptStr);
// const scriptObj = document.createElement('script');
// scriptObj.src = newUrl;
// scriptObj.setAttribute('onerror', 'handError(this)');
// scriptObj.setAttribute('onload', 'handLoad(this)');
// document.body.appendChild(scriptObj);
};
const handLoad = (srcEle) => {
console.log(srcEle.src, ' is loaded');
};
window.addEventListener('DOMContentLoaded', () => {
console.log('DOMContentLoad');
});
</script>
<div>demo</div>
<script defer src="./1.js" onerror="handError(this)" onload="handLoad(this)"></script>
<script defer src="./2.js" onerror="handError(this)" onload="handLoad(this)"></script>
<script defer src="./3.js" onerror="handError(this)" onload="handLoad(this)"></script>
</body>
</html>
为什么使用doeument.write不能重载异步脚本2.js和3.js,而使用appendChild能全部重载。图3为注释write使用appendChild的结果,图4为删除defer属性后使用write能够正常重载。
目前估计产生问题的原因在:defer属性的异步加载脚本与DOMContentLoaded以及document.write的这三者之间有某种连系,导致在第一次写入脚本后,覆盖了页面,并一直处于DOMContentLoaded前的状态。具体是什么原因导致的,希望大神们能解惑。
异步加载的脚本会在docuemnt的readyState属性变成了interactive后执行,但此时文档流已经关闭了,在使用write进行写入就会默认执行document.open()打开新的文档流进行写入,所以会覆盖页面。并且在执行write后,没有调用document.close()关闭文档流,所以浏览器会一直处于解析状态,即DOMContentLoaded之前。