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

基于Express+axios实现菜单切换时动态加载JS仅执行一次如何解决?

问题根本原因

浏览器对 type="module" 的ES模块有全局单例缓存规则,同一个URL的模块仅会被下载、解析、执行一次。你第一次插入脚本时模块正常执行,后续重复插入同URL的脚本节点时,浏览器会直接复用已缓存的模块实例,不会重新运行模块内的顶层代码,所以看起来脚本没有生效。

解决方案

方案1:加随机查询参数强制刷新模块(改动最小,快速生效)

直接给动态加载的脚本URL拼接时间戳或随机数作为查询参数,让每次请求的URL唯一,跳过模块缓存,仅需修改一行代码:

// 原代码
script.setAttribute('src', `/js/pages/ui-${event.value}-controller.mjs`);
// 改为
script.setAttribute('src', `/js/pages/ui-${event.value}-controller.mjs?t=${Date.now()}`);

该方案改动量极小,适合快速验证修复效果,缺点是每次切换路由都会重新请求脚本文件,有少量额外网络开销。

方案2:缓存模块导出的初始化方法(性能最优,推荐生产环境使用)

将对应页面的控制器逻辑封装为可重复调用的初始化函数导出,第一次加载模块后缓存导出的方法,后续切换回对应页面时直接调用初始化方法即可,无需重复插入脚本。

修改后的控制器逻辑:

// 全局缓存已加载的控制器模块
const loadedControllers = new Map();

const mainSidebarUiMouseclick = async (event) => {
  const content = document.getElementById('content');
  const pageKey = event.value;

  // 清空内容前可调用前一个页面的destroy方法清理资源
  content.innerHTML = '';

  try {
    // 加载页面内容
    const res = await axios.get(`${window.location.href}/${pageKey}`);
    content.innerHTML = res.data;

    // 已加载过模块,直接调用初始化方法
    if (loadedControllers.has(pageKey)) {
      loadedControllers.get(pageKey).init();
      console.info(`@system, 页面控制器已复用`);
      return;
    }

    // 首次加载对应模块
    switch(pageKey) {
      case 'diary':
        const module = await import(`/js/pages/ui-${pageKey}-controller.mjs`);
        // 缓存模块导出的方法
        loadedControllers.set(pageKey, module);
        // 调用初始化方法执行页面逻辑
        module.init();
        console.info(`@system, 动态脚本加载完成`);
        break;
      // 其他页面逻辑同理
    }
  } catch (error) {
    console.error(`@error, ${error}`);
  }
};

同步修改对应的控制器脚本(比如ui-diary-controller.mjs),把原有顶层执行逻辑封装为导出方法:

// 页面初始化逻辑封装为init函数导出
export function init() {
  // 原有页面逻辑:绑定事件、渲染数据等
  const diaryList = document.querySelector('#diary-list');
  // ...
}

// 可选导出销毁方法,切换路由时清理资源避免内存泄漏
export function destroy() {
  // 移除绑定的事件、取消未完成的请求、清理定时器等
}

该方案避免了重复的网络请求,性能更好,也方便统一管理页面生命周期。

补充注意事项

  • 如果采用方案1,且脚本内绑定了DOM事件,记得每次执行时先移除旧的事件监听,避免重复绑定导致异常。
  • 切换路由清空内容前,建议先清理前一个页面的未完成异步请求、定时器等资源,避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 10:18:00