JavaScript动态导入(import())自动缓存同一URL模块,后续调用返回已解析Promise;需确保路径字符串完全一致(含大小写、参数)、模块为有效ESM,避免时间戳或随机数等破坏缓存的动态拼接。

JavaScript 动态导入(import())本身会自动缓存已加载的模块,**同一 URL 的模块只会执行一次,后续调用返回已解析的 Promise**。这是规范行为,无需手动干预,但需注意几个关键点才能真正利用好这个缓存机制。
模块 URL 必须完全一致
缓存以模块标识符(即 import() 中的字符串参数)为键。只要字符串内容相同(包括大小写、斜杠、查询参数),浏览器或运行时就视为同一模块:
-
import('./utils.js')和import('./utils.js')→ ✅ 缓存生效 -
import('./utils.js')和import('./utils.js?123')→ ❌ 视为不同模块,重复加载 -
import('./utils.js')和import('./Utils.js')(在区分大小写的文件系统中)→ ❌ 可能不命中缓存
模块必须是有效的 ES 模块且无副作用干扰
缓存的是模块实例(module record),不是源码。但以下情况可能导致“看似没缓存”:
- 模块导出的是对象字面量或函数调用结果(如
export default { count: 0 }),每次导入拿到的是同一个对象引用,但内部状态可能被修改 —— 这不是缓存失效,而是模块状态被共享了 - 模块顶层有副作用代码(如
console.log('loaded')),它只在首次执行时运行,后续import()返回已执行完毕的模块,不会重复打印 - 若模块依赖的嵌套模块变更(如
a.js导入b.js,而b.js被热更新),则整体缓存可能被绕过(取决于构建工具或运行时环境)
避免常见误操作破坏缓存
有些写法看似动态,实则每次都生成新 URL,导致无法复用缓存:
立即学习“Java免费学习笔记(深入)”;
- 拼接时间戳:
import(`./mod.js?t=${Date.now()}`)→ ❌ 永远不缓存 - 随机数或哈希未固定:
import(`./mod.js?v=${Math.random()}`)→ ❌ 同样失效 - 路径拼接错误:
import(`${base}/mod.js`)中base值不一致 → ❌ 键不同 - 正确做法:确保字符串字面量或变量值稳定,例如用常量、配置项或服务端下发的确定版本号
验证是否命中缓存的小技巧
可在模块顶层加一个标志,观察控制台输出次数:
/* logger.js */
console.log('[logger] module evaluated');
export const log = (msg) => console.log(msg);然后多次调用:
import('./logger.js').then(m => m.log('first'));
import('./logger.js').then(m => m.log('second'));如果只看到一次 [logger] module evaluated,说明缓存生效;两次则说明 URL 不一致或环境异常(如开发服务器禁用了模块缓存)。


















