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

如何用类实现外部jQuery库加载执行?解决fetch调用报错问题

问题描述

尝试编写类来加载remodal.js、datatables.js等外部jQuery库并执行逻辑,但类版本的loadFile方法抛出错误:

VM1903:10 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'map')
at eval (eval at (script.js:10:21), :10:4806)
at eval (eval at (script.js:10:21), :10:148)
at eval (eval at (script.js:10:21), :10:171)
at script.js:10:21

此前普通函数版本可正常运行,代码如下:

正常运行的函数版代码

JavaScript

const sources = [
  {
    path: 'https://cdnjs.cloudflare.com/ajax/libs/remodal/1.1.1/remodal.min.js',
    callback: null
  },
  {
    path: 'https://cdn.datatables.net/1.12.1/js/jquery.dataTables.min.js',
    callback: () => { document.getElementById('example').DataTable(); }
  },
]
sources.forEach(source => loadFile(source));

function loadFile(source) {
  fetch(source.path)
    .then(data => data.text())
    .then(text => eval(text))
    .then(() => source.callback);
}

HTML

<script src="https://code.jquery.com/jquery-3.6.1.min.js"
    integrity="sha256-o88AwQnZB+VDvE9tvIXrMQaPlFFSUTR+nldQm1LuPXQ=" crossorigin="anonymous"></script>

<a id="remodalOn" href="#modal">Click me!</a>
<div class="remodal" data-remodal-id="modal">
  <button data-remodal-action="close" class="remodal-close">Close modal</button>
  <h1>Remodal Test</h1>
  <table id="example">
    <thead>
      <tr>
        <th>Given name</th>
        <th>Surname</th>
        <th>Age</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>Harry</td>
        <td>Potter</td>
        <td>17</td>

      </tr>
      <tr>
        <td>Lily</td>
        <td>Potter</td>
        <td>40</td>
      </tr>
    </tbody>
  </table>
</div>

报错的类版代码

JavaScript

class ExternalJSfile {
  constructor(path, callback = null) {
    this.path = path;
    this.callback = callback;
  }

  loadFile() {
    fetch(this.path)
      .then(data => data.text())
      .then(text => eval(text))
      .then(() => this.callback);
  }
}

// Load remodal.js
const remodal = new ExternalJSfile(
  'https://cdnjs.cloudflare.com/ajax/libs/remodal/1.1.1/remodal.min.js'
);
remodal.loadFile();

// Load datatables.js and then execute .DataTable()
const dataTables = new ExternalJSfile(
  'https://cdn.datatables.net/1.12.1/js/jquery.dataTables.min.js',
  () => { document.getElementById('example').DataTable() }
);
dataTables.loadFile();

HTML

<script src="https://code.jquery.com/jquery-3.6.1.min.js"
    integrity="sha256-o88AwQnZB+VDvE9tvIXrMQaPlFFSUTR+nldQm1LuPXQ=" crossorigin="anonymous"></script>
    
<a id="remodalOn" href="#modal">Click me!</a>
<div class="remodal" data-remodal-id="modal">
  <button data-remodal-action="close" class="remodal-close">Close modal</button>
  <h1>Remodal Test</h1>
  <table id="example">
    <thead>
      <tr>
        <th>Given name</th>
        <th>Surname</th>
        <th>Age</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>Harry</td>
        <td>Potter</td>
        <td>17</td>

      </tr>
      <tr>
        <td>Lily</td>
        <td>Potter</td>
        <td>40</td>
      </tr>
    </tbody>
  </table>
</div>
问题分析与解决方案

错误原因

  1. 作用域问题:类方法中的eval默认在方法局部作用域执行,外部库无法正确挂载到全局对象(比如jQuery的$),导致库内部调用map等方法时找不到依赖对象。
  2. 回调未执行:代码中仅引用了回调函数,没有实际调用(then(() => this.callback)应该改为执行函数)。
  3. 并行加载冲突:类版同时触发两个库的加载,可能导致依赖jQuery的库在未完全初始化时就执行逻辑。

正确的类实现方案

核心改进点

  • 让eval在全局作用域执行,确保库挂载到window。
  • 修复回调执行逻辑。
  • 支持顺序加载,避免依赖冲突。

修正后的类代码

class ExternalJSfile {
  constructor(path, callback = null) {
    this.path = path;
    this.callback = callback;
  }

  async loadFile() {
    try {
      const response = await fetch(this.path);
      const text = await response.text();
      // 强制在全局作用域执行脚本,确保库正确挂载
      (0, eval)(text);
      // 执行回调(存在时)
      this.callback?.();
    } catch (error) {
      console.error(`加载文件失败: ${this.path}`, error);
    }
  }

  // 静态方法:按顺序加载多个文件,处理依赖关系
  static async loadSequentially(files) {
    for (const file of files) {
      const loader = new ExternalJSfile(file.path, file.callback);
      await loader.loadFile();
    }
  }
}

// 推荐:顺序加载(避免依赖冲突)
const sources = [
  {
    path: 'https://cdnjs.cloudflare.com/ajax/libs/remodal/1.1.1/remodal.min.js'
  },
  {
    path: 'https://cdn.datatables.net/1.12.1/js/jquery.dataTables.min.js',
    callback: () => { document.getElementById('example').DataTable(); }
  }
];
ExternalJSfile.loadSequentially(sources);

说明

  • (0, eval)(text)是将eval转为全局作用域执行的技巧,确保外部库能正确绑定到window对象。
  • 使用async/await替代链式then,代码更简洁,也方便实现顺序加载。
  • 增加错误捕获,便于调试加载失败场景。
  • 静态方法loadSequentially支持按顺序加载多个文件,适合有依赖关系的库。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 14:45:33