HTTP/2多路复用由协议层自动启用,无需JavaScript或HTML手动开启;关键在于统一主域名、用modulepreload提前触发关键模块请求并设as属性、避免子域名拆分导致连接隔离、验证Protocol为h2且Connection ID一致。

统一资源域名,让所有模块共享一个连接
即使你用 import { foo } from './utils/bar.js' 或动态 import('./features/chart.mjs'),如果这些路径被代理到不同子域名(如 https://js.example.com/、https://mod.example.com/),浏览器就得为每个域名单独建 TLS 连接——多路复用流 ID 不互通,优先级无法协同。实测显示,4 个子域名在 HTTP/2 下反而比单域名慢 15% 以上。
建议做法:
- 静态资源全部托管在主域名下,例如
https://example.com/js/utils/bar.js - Vite 或 Webpack 构建时配置
publicPath: '/'或assetPrefix: '',避免生成跨域 URL - CDN 回源配置强制收敛到同一 origin,不暴露子域别名
用 rel="modulepreload" 提前抢占复用通道
普通 import 是解析执行时才触发请求,中间存在几十毫秒空窗;而 <link rel="modulepreload" href="/js/core.mjs" as="script"> 能在 HTML 解析早期就发起请求,把复用连接的带宽和流优先级提前占住。
注意要点:
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 必须加
as="script",否则浏览器不会设置正确的 MIME 类型和缓存策略 - 只对首屏强依赖模块使用(如路由入口、核心工具函数),非关键模块会挤占关键资源带宽
- 它不执行代码,只是预加载;后续仍需
import或import()触发执行
慎用动态 import,优先合并高频微模块
HTTP/2 多路复用擅长并发传多个小文件,但前提是这些请求能被浏览器“看到”并统一调度。而过度碎片化的 import('./a.mjs'); import('./b.mjs'); import('./c.mjs') 在 Vite 开发模式下可能被转成独立请求,若未配合 preload 或正确分组,容易因 JS 执行顺序或 Promise 微任务排队导致实际发出时间错开,浪费复用潜力。
更优策略:
- 将语义紧密、调用频率高的微模块打包进同一 chunk(如
ui-primitives.mjs),减少请求数而非盲目拆分 - 对真正按需的模块(如编辑器插件、报表导出),用
import()+Promise.all显式并发加载,确保浏览器一次性发起多个请求 - 避免在循环中逐个
import(),改用数组映射后Promise.all(imports.map(...))
验证是否真正在复用,别信瀑布图直觉
打开 Chrome DevTools → Network → 刷新页面 → 点击任意 JS 请求 → 查看 Headers 标签页中的 Protocol 字段是否为 h2;再对比多个 JS 请求的 Connection ID 是否一致(可在 Connection 列右键显示该字段)。只有 Protocol 是 h2 且 Connection ID 相同,才说明它们跑在同一条多路复用通道上。
常见失效信号:
- 同域名下部分请求显示
http/1.1:可能是证书不支持 ALPN,或 Nginx 未开启http2监听 - 多个 JS 请求 Connection ID 不同:存在重定向、SNI 不一致、或 CDN 中间层降级
- 请求时间轴呈明显串行:检查是否有同步脚本阻塞 HTML 解析,导致后续
import标签延迟触发

















