为什么用了HTTP/2多路复用后图片加载反而更慢了?
我在优化网站时启用了HTTP/2,按理说多路复用应该更快,但发现首页轮播图的加载时间反而比HTTP/1.1多了200ms左右。检查网络面板发现,虽然所有图片都走同一个连接,但请求顺序好像被打乱了。
尝试过用fetch()设置优先级:
const controller = new AbortController();
controller.signal.addEventListener('abort', () => {
console.log('Request canceled');
});
// 设置高优先级的fetch请求
fetch('/images/banner.jpg', {
method: 'GET',
headers: { 'Priority': 'u=1' }, // 这样设置对吗?
signal: controller.signal
});
但浏览器开发者工具里没看到优先级生效的迹象。服务器是Nginx 1.20,配置了http2 on;,且测试工具显示确实支持HPACK压缩。难道HTTP/2的优先级需要服务端特殊配置?还是我的代码写法有问题?
HTTP/2 的优先级机制确实存在,但它不是靠你在 fetch 里塞个 Priority 头就能生效的。这个优先级信息要通过 HTTP/2 协议层的“权重”和“依赖关系”来传递,而这些底层控制权不在客户端 JS 手上,浏览器会自己决定怎么排序请求,你的 headers 设置基本被忽略。
真正影响加载顺序的是浏览器的内部调度策略。比如你页面里的 img 标签,浏览器会根据渲染树自动提升它们的优先级,但如果你用 fetch 去拉图片再塞进 DOM,那它就被当成“低优先级资源”处理了——即使你写了高优先级头,fetch 默认还是走的是“脚本发起”的流程,不会提升到图片应有的等级。
解决办法有几个:
第一,别用 fetch 拉关键图片。轮播图这种视觉核心内容,直接用
第二,如果非得用 JS 控制,可以用 preload 提示浏览器预加载:
或者在 JS 里动态创建 Image 对象:
const img = new Image();
img.src = '/images/banner.jpg'; // 浏览器会正确识别优先级
第三,服务端 Nginx 虽然开了 http2 on;,但默认不会做请求重排或优先级重写。你可以考虑配合使用 Link 头部做服务器推送(虽然现在用得少了),或者确保关键资源在 HTML 中尽早出现。
总结一下:HTTP/2 多路复用本身没错,慢是因为你把本该高优的资源用低优方式请求了。别迷信 fetch + 自定义头,浏览器对资源类型的原生语义才是优先级的关键。换成 img 或 preload,你会发现加载时机立马改善。