当前位置: 首页 > 知识库问答 >
问题:

javascript - 为什么使用document.write不能重载多个defer脚本?

翟曦之
2024-08-26
<!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使用write的结果
目前估计产生问题的原因在:defer属性的异步加载脚本与DOMContentLoaded以及document.write的这三者之间有某种连系,导致在第一次写入脚本后,覆盖了页面,并一直处于DOMContentLoaded前的状态。具体是什么原因导致的,希望大神们能解惑。

共有1个答案

甄成弘
2024-08-26

在解释为什么使用 document.write 不能重载多个带有 defer 属性的脚本,而使用 appendChild 可以成功重载所有脚本之前,我们需要理解几个关键概念和它们之间的相互作用。

1. defer 属性的作用

<script> 标签具有 defer 属性时,它告诉浏览器该脚本将延迟执行,直到文档完全解析和显示之后(即 DOMContentLoaded 事件触发之后),并且脚本将按照它们在文档中出现的顺序执行。

2. document.write 的行为

document.write 方法主要用于在文档加载和解析过程中向文档输出内容。然而,一旦文档加载完成(即 DOMContentLoaded 事件触发后),再调用 document.write 会导致页面被重写,这通常不是你想要的结果。在这种情况下,它会导致整个页面内容被新的 <script> 标签替换,从而中断当前脚本的执行和其他任何 defer 脚本的加载和执行。

3. 问题解释

在你的例子中,当第一个 defer 脚本(如 ./1.js)发生错误时,handError 函数被调用,它试图通过 document.write 动态添加一个新的 <script> 标签来“重载”脚本。然而,由于此时文档可能已经完成了加载(至少是 DOMContentLoaded 事件已经触发),document.write 的调用会重写整个页面,包括已经加载的 DOM 和后续将要加载的 defer 脚本(如 ./2.js./3.js)。因此,这些脚本不再加载或执行。

4. 为什么 appendChild 可以工作

使用 appendChild 方法动态添加 <script> 标签不会重写整个页面,而是将新的 <script> 元素添加到 DOM 中。这允许页面保持其现有内容不变,并且新的脚本标签可以像页面中的其他脚本一样正常加载和执行,即使它们是在 DOMContentLoaded 事件之后添加的。

结论

因此,当你需要在文档加载完成后动态添加脚本时,应该使用 appendChild 或其他 DOM 操作方法,而不是 document.write。这样可以避免重写整个页面并保留页面的当前状态,包括已经加载和将要加载的其他脚本。

 类似资料:
  • 问题内容: 我知道这被认为是不良做法;并且,我希望整理出一份为什么要向第三方供应商提交的原因清单,说明为什么他们不应该在其分析代码的实现中使用它们。 请在下面说明您提出不良做法的理由。 问题答案: 一些较严重的问题: document.write(此后称为DW)在XHTML中不起作用 DW不会直接修改DOM,从而阻止了进一步的操作 (试图寻找证据,但充其量只是视情况而定) 页面加载完成后执行的DW

  • 问题内容: 在教程中,我学会了使用。现在,我了解到,很多人对此表示反对。我已经尝试过,但随后它实际上将其发送到打印机。 那么我应该使用哪些替代方法,为什么不使用呢?w3schools和MDN都使用。 问题答案: 作为推荐的替代方法,您可以使用DOM操作直接查询节点元素并将其添加到DOM。

  • chrome浏览器 onclick链接 O:https://www.w3schools.com窗口打开 X:about:空白窗口打开

  • 我无法理解为什么以下操作不起作用? 我一直收到错误: 我尝试使用通用参数: 我好像想不出来。 我完全错过了什么? 我正在使用OpenJDK 11。

  • 如果我的理解是正确的,那么为什么不将的==和!=运算符重载为: 那我们就可以省下两个铸件了?