动态导入(import())本身不干预浏览器缓存,但与之天然协同:服务端正确配置缓存头后,模块文件按标准http缓存流程复用;构建工具生成的哈希文件名确保内容变更时自动失效旧缓存,配合es6模块单例机制实现网络与执行双重优化。

动态导入(import())本身不干预浏览器缓存,但它和浏览器缓存天然协同——只要服务端正确配置了缓存响应头,动态加载的模块文件就会被正常缓存,后续请求直接复用。
动态导入触发的请求走标准缓存流程
调用 import('./module.js') 时,浏览器会发起一个普通的 GET 请求,这个请求完全遵循 HTTP 缓存规则:
- 如果响应头含
Cache-Control: max-age=3600,且未过期,下次同路径导入会直接从磁盘或内存缓存读取,Network 面板显示 200 (from disk cache) - 如果缓存过期或设了
no-cache,浏览器会发带If-None-Match或If-Modified-Since的协商请求,服务器返回 304 就复用本地副本 - 若服务端返回
no-store,则每次都会重新下载,无法缓存
文件名哈希是缓存更新的关键配合点
动态导入的模块路径通常由构建工具生成,比如 chunk.abc123.js。这种哈希命名和浏览器缓存机制形成闭环:
- 内容不变 → 哈希不变 → 文件名不变 → 浏览器继续用强缓存
- 内容变了 → 哈希变 → 文件名变 → 浏览器视为全新资源,跳过旧缓存,发起新请求
- 这样就避免了“JS 更新了但用户还在用旧缓存”的问题,无需手动清缓存或加时间戳
ES6 模块自身的缓存机制也起作用
即使多次执行 import('./utils.js'),JavaScript 引擎也只执行一次模块代码,后续导入都返回同一个模块实例:
- 这是 ES6 模块的单例特性,与 HTTP 缓存无关,但叠加后效果更强:既省网络,又免重复执行
- 注意:路径必须完全一致(包括查询参数),
./utils.js?v=1和./utils.js?v=2被视为两个不同模块 - 模块缓存存在于内存中,页面刷新即失效;而 HTTP 缓存可跨会话持久存在
Service Worker 可进一步增强控制力
如果你需要离线可用或自定义缓存策略,可在 Service Worker 中拦截动态导入的请求:
- 用
caches.match()先查 Cache API 是否有该模块 - 命中则直接返回;未命中再
fetch()并存入缓存 - 这样能绕过默认的 HTTP 缓存逻辑,实现版本灰度、预加载或降级策略











