You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用document.writeln加载S3预签名URL内容时远程jQuery无法加载

问题描述

尝试从S3预签名URL动态加载内容,使用document.writeln()实现,但远程jQuery及其他库无法正常加载,报错:

VM413:1 Uncaught ReferenceError: $ is not defined at :1:1

使用的代码如下:

var url = "S3 Pre-signed url";

fetch(url).then(response => response.text()).then(data => {
  var lines = data.split("\n");
  for (var i = 0; i < lines.length; i++) {
    var line = lines[i];
    if (line.toUpperCase().indexOf("<SCRIPT ") >= 0) {
      if (line.indexOf("$") < 0) {
        var index1 = line.toUpperCase().indexOf("<SCRIPT ");
        var before_line = line.substring(0, index1 - 9);

        var index2 = line.indexOf(">");
        var sub = line.substring(index1 - 8, index2);
        var after_line = line.substring(index2 + 1);
        //var sub2  = sub.substring(0,index2-1);

        sub += " async >";
        //sub = sub.replace(/"/g, '\"");
        var line2 = before_line + sub + after_line;

        line2 = line2.replace(/<\/script>/g, "<\/script>")
        document.writeln(line2)
      } else {
        //console.log("Index of $")
        document.writeln(line)
      }
    } else {
      document.writeln(line)
    }
  }
})
问题原因
  1. document.writeln()的局限性:若在页面加载完成后调用该方法,会清空当前文档并创建新文档,导致已加载的脚本丢失;即便在页面加载中使用,也难以精准控制脚本的加载顺序。
  2. 盲目添加async属性:给jQuery脚本强制添加async会使其异步加载,而依赖jQuery的脚本(含$的代码)可能提前执行,此时jQuery尚未加载完成,就会触发$ is not defined错误。
  3. 按行拆分HTML的风险:HTML标签(包括<script>)可能跨多行,用split("\n")拆分后会破坏标签结构,导致脚本无法被正确解析执行。
解决方案

1. 改用DOM操作加载内容,弃用document.writeln()

使用DOMParser解析完整的HTML字符串,再将解析后的节点插入页面,能完整保留原HTML的结构和逻辑。

2. 严格控制脚本加载顺序

对于有依赖关系的脚本(比如必须先加载jQuery),通过监听脚本的load事件实现顺序加载,确保依赖库加载完成后再执行后续脚本。

修改后的代码示例

var url = "S3 Pre-signed url";

fetch(url)
  .then(response => response.text())
  .then(html => {
    // 解析HTML内容为DOM节点
    const parser = new DOMParser();
    const doc = parser.parseFromString(html, 'text/html');
    
    // 提取页面内容和所有脚本标签
    const bodyContent = doc.body.innerHTML;
    const scripts = Array.from(doc.querySelectorAll('script'));
    
    // 先插入非脚本内容到页面
    document.body.insertAdjacentHTML('beforeend', bodyContent);
    
    // 递归按顺序加载脚本
    const loadNextScript = (index) => {
      if (index >= scripts.length) return;
      
      const originalScript = scripts[index];
      const newScript = document.createElement('script');
      
      // 复制原脚本的所有属性(如src、type等)
      for (const attr of originalScript.attributes) {
        newScript.setAttribute(attr.name, attr.value);
      }
      
      // 处理内联脚本内容
      if (originalScript.textContent) {
        newScript.textContent = originalScript.textContent;
      }
      
      // 当前脚本加载完成后,加载下一个脚本
      newScript.onload = () => loadNextScript(index + 1);
      newScript.onerror = () => loadNextScript(index + 1); // 忽略错误继续加载后续脚本
      
      document.body.appendChild(newScript);
    };
    
    // 启动脚本加载流程
    loadNextScript(0);
  });

额外提示

  • 如果原HTML中的脚本有明确的依赖优先级(比如jQuery必须最先加载),可以手动调整scripts数组的顺序,确保依赖库排在最前面。
  • 不要随意给依赖类脚本添加async或defer属性,除非能确保依赖顺序不受影响。

内容的提问来源于stack exchange,提问作者chiku

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 16:54:56