SSF0SSF0
首页
前端
  • Node
  • Go
  • C#
  • MySql
  • Bash
  • Git
  • Docker
  • VuePress
  • CI/CD
  • 服务器
  • 网站
  • 学习资料
  • 软件
Timeline
Github
标签
分类
首页
前端
  • Node
  • Go
  • C#
  • MySql
  • Bash
  • Git
  • Docker
  • VuePress
  • CI/CD
  • 服务器
  • 网站
  • 学习资料
  • 软件
Timeline
Github
标签
分类
  • HTML

    • html1
    • html2
  • CSS

    • Flex 布局常见问题与解决方案
  • JavaScript

    • 数据类型及引用问题
    • 处理 Blob 类型文件下载问题总结
    • localStorage 与 sessionStorage 区别
    • JavaScript 中的 script 标签问题详解
    • JavaScript 中的`this`指向问题详解
    • SessionStorage踩坑记录:它真的能"只设置一次"吗?
    • 动态加载 JS 脚本方法对比
    • 浏览器页面关闭场景下的数据上报
  • es6

    • Promise
    • es6 模块导出方式全解析
  • Vue2

    • created VS mounted 发起异步请求
    • vue2-2
  • Vue3

    • Vite + Vue3 修改 element-plus 源码
    • Vue v-if 与 v-show
    • Vue3 ref 获取组件
    • Vue3 路由传参
    • 父子组件与组件里 Hooks 加载顺序
    • 第三方组件传入参数TS提示
    • Vue3 Props 在 Hooks 中的响应性处理
    • Vue Router 的两种历史模式及部署配置详解
    • 在Vue 3项目中顺利集成Tailwind CSS的完整指南
    • Vue 3 深度选择器:deep()完全指南
  • Electron

    • 快速构建 electron + vue3 项目
  • TS

    • TS 泛型
    • 记录模板使用断言的问题
    • type 与 interface
  • WebPack

    • Webpack 介绍
  • Vite

    • Vite CLI 常见命令
    • vite 与 webpack 比较
  • 项目工程

    • 前端代码风格
    • Vue3 项目规范
    • npm 镜像问题
    • 包管理工具
    • 使用 engines 限制开发环境依赖
    • 打包与shell交互指定模式
    • 使用 pnpm 构建 Monorepo 实战指南
    • pnpm 修改依赖源码打包报错
  • 记录一下小程序
  • 控制浏览器正确保存网站账号密码的技巧

动态加载 JS 脚本方法对比

在前端开发中,我们经常需要在一个 JavaScript 文件中动态加载其他外部 JS 文件(而且要等加载成功后执行后续的逻辑)。主要有两种方式可以实现:使用<script>标签和使用fetch API。本文将对比这两种方法的异同、适用场景和潜在问题。

1. Script 标签加载方式

基本原理

通过动态创建<script>标签并设置其src属性,将标签添加到 DOM 中,浏览器会自动加载并执行该脚本。

代码示例

function loadScriptWithTag(url, callback) {
  const script = document.createElement("script");
  script.src = url;

  // 加载成功回调
  script.onload = function () {
    console.log(`脚本加载成功: ${url}`);
    if (callback) callback(true);
  };

  // 加载失败回调
  script.onerror = function () {
    console.error(`脚本加载失败: ${url}`);
    if (callback) callback(false);
  };

  // 添加到文档中开始加载
  document.head.appendChild(script);
}

// 自执行
loadScriptWithTag(
  "https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js",
  function (success) {
    console.log("脚本加载成功:", success);
    // 确保加载成功,执行后续的逻辑
    console.log(_.join(["a", "b", "c"], "~"));
  }
);

优点

  1. 跨域支持:不受同源策略限制,可以加载任何域的脚本

  2. 全局作用域:加载的脚本直接在全局作用域中执行,自动注册全局对象和函数

  3. 浏览器缓存:浏览器会自动缓存脚本文件,提高重复访问性能

  4. 执行可靠:加载完成后立即执行,执行环境与主页面一致

缺点

  1. 无法访问脚本内容:只能执行脚本,无法直接获取或修改脚本内容

  2. 无法预处理:无法在执行前对代码进行修改或检查

  3. 错误处理有限:出错时只能知道加载失败,无法获得详细错误信息

2. Fetch API 加载方式

基本原理

使用fetch API 获取脚本文件内容作为文本,然后使用eval或Function构造函数将文本作为 JavaScript 执行。

代码示例

function loadScriptWithFetch(url) {
  return fetch(url)
    .then((response) => {
      if (!response.ok) {
        throw new Error(`HTTP error! Status: ${response.status}`);
      }
      return response.text();
    })
    .then((code) => {
      // 使用eval执行代码
      console.log(`脚本加载成功: ${url}`);
      eval(code);

      if ("判断一下脚本里面的方法是否存在") {
        // 确保加载成功,执行后续的逻辑
      }
      return true;
    })
    .catch((error) => {
      console.error(`脚本加载失败: ${url}`, error);
      return false;
    });
}
  • 调用 eval(code) 时,浏览器会立即、同步地解析并执行这段字符串代码,也就是说:

    • 它会阻塞当前线程,直到执行完成。

    • 如果里面有语法错误或运行错误,会立即抛出异常。

    • 如果里面包含函数定义、变量声明等,执行完成后立即生效。

优点

  1. 内容可见:可以访问和修改脚本内容后再执行

  2. 更好的错误处理:可以捕获 HTTP 错误和响应细节

  3. 可以预处理:可以在执行前对代码进行分析、转换或注入依赖

缺点

  1. 跨域限制:受同源策略限制,加载跨域脚本需要目标服务器配置 CORS

  2. 作用域问题:通过 eval 执行的代码可能在不同的词法环境中,导致全局变量和函数无法正确注册

  3. 安全限制:现代浏览器对 eval 有更多限制,某些环境下可能被限制使用

3. 比较和适用场景

特性Script 标签Fetch API
跨域加载✅ 支持❌ 需要 CORS
执行可靠性✅ 高❌ 可能有作用域问题
内容可修改❌ 不可修改✅ 可修改
错误处理❌ 简单✅ 详细

适用场景推荐

  • 使用 Script 标签加载的场景:

    • 加载第三方库和框架

    • 需要在全局作用域中注册对象或函数

    • 需要跨域加载脚本

    • 加载后立即使用库的功能

  • 使用 Fetch 加载的场景:

    • 需要检查或修改脚本内容

    • 只在同源环境下使用

    • 需要对加载过程有更精细的控制

4. 最佳实践

  1. 首选 Script 标签:对于大多数情况,特别是加载外部库,使用 Script 标签更可靠

  2. 添加超时处理:为脚本加载添加超时机制

  3. 提供备用方案:当主要 CDN 加载失败时,尝试备用源

  4. 检查已加载:避免重复加载同一脚本

5. 结论

在大多数情况下,使用 Script 标签加载外部 JS 文件是更可靠的选择,特别是当加载的脚本需要在全局作用域中注册函数或对象时。Fetch 方法虽然提供了更多的灵活性,但存在跨域限制和作用域问题,使用时需要格外小心。

最后更新时间:
贡献者: 何风顺
上一页
SessionStorage踩坑记录:它真的能"只设置一次"吗?
下一页
浏览器页面关闭场景下的数据上报