浏览器缓存显著影响esm加载速度,关键在url缓存匹配、合理缓存策略及模块图解析时的请求控制;静态路径易命中强缓存,带哈希路径可规避旧版问题,查询参数可能被cdn忽略;cache-control头决定缓存行为,modulepreload可提前预加载,动态import需确保url一致性。

浏览器缓存对ESM模块加载速度有显著影响,关键在于模块的URL是否被缓存、缓存策略是否合理,以及模块图解析过程中是否重复请求。
模块URL决定缓存行为
ESM通过import语句加载模块时,浏览器依据模块的完整URL(含协议、域名、路径、查询参数)进行缓存匹配。同一URL在缓存有效期内不会重新请求,直接复用已缓存的响应内容。
- 静态路径如
import { foo } from './utils.js',URL相对确定,容易命中强缓存(如Cache-Control: max-age=31536000) - 带版本或哈希的路径如
./utils.a1b2c3.js,每次构建变更URL,天然规避缓存旧版本,但需确保服务端对这类资源配置长期缓存 - 含查询参数的路径如
./module.js?v=1.2.0,部分CDN或代理可能忽略查询参数缓存,导致重复请求;推荐用文件名哈希替代查询参数
HTTP缓存头直接影响首次与后续加载
模块资源响应头中的Cache-Control和ETag/Last-Modified共同决定浏览器是否发起网络请求。
-
Cache-Control: public, max-age=31536000:静态模块可设为一年,浏览器跳过请求直接读缓存 -
Cache-Control: no-cache:强制每次校验(发送If-None-Match),增加RTT但避免内容过期 -
Cache-Control: no-store:完全禁用缓存,所有模块都重新下载——开发环境调试时可能启用,但严重拖慢加载速度
模块图解析阶段无法跳过网络请求(即使缓存存在)
浏览器在首次解析模块图(module graph)时,仍需发起初始请求以获取入口模块内容,进而解析import语句、发现依赖。这个过程无法绕过网络,但后续相同模块的导入会立即命中内存缓存或HTTP缓存。
- 同一页面中多次
import 'lib.js',仅首次触发网络请求,其余直接复用已解析的模块实例 - 跨页面或刷新后,若HTTP缓存有效,则模块脚本本身不重传,但解析和执行流程仍需走一遍
- 使用
<link rel="modulepreload">可提前触发关键模块的预加载,让缓存就绪时间前移,减少主模块解析阻塞
动态import()与缓存的关系更灵活
动态导入返回Promise,其模块URL可拼接变量,适合按需加载。缓存行为依然取决于最终生成的URL,但因运行时构造,需特别注意缓存一致性。
- 例如
import(`./pages/${page}.js`),不同page值对应不同URL,各自独立缓存 - 若URL构造逻辑出错(如路径未标准化、大小写混用),可能导致同一模块被当作多个资源重复缓存或漏缓存
- 服务端可配合
Vary: Accept等头支持内容协商,但ESM目前不支持根据Accept自动选择模块格式,建议统一输出标准ESM
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











