我认为这是 Chrome 中的一个错误,或者至少是一个不必要的限制。
这很容易测试。
我创建了一个简单的示例 HTML 文件,它下载了相同 javascript 文件的 25 个副本(使用查询参数使其看起来像不同的资源):
<!DOCTYPE HTML>
<html>
<head>
<title>Test for Lots of JS files</title>
<meta name="robots" content="noindex">
<body>
</body>
<h1>This is a test for Lots of JS files</h1>
<script src="/assets/js/test.js?v=01"></script>
<script src="/assets/js/test.js?v=02"></script>
<script src="/assets/js/test.js?v=03"></script>
<script src="/assets/js/test.js?v=04"></script>
<script src="/assets/js/test.js?v=05"></script>
<script src="/assets/js/test.js?v=06"></script>
<script src="/assets/js/test.js?v=07"></script>
<script src="/assets/js/test.js?v=08"></script>
<script src="/assets/js/test.js?v=09"></script>
<script src="/assets/js/test.js?v=10"></script>
<script src="/assets/js/test.js?v=11"></script>
<script src="/assets/js/test.js?v=12"></script>
<script src="/assets/js/test.js?v=13"></script>
<script src="/assets/js/test.js?v=14"></script>
<script src="/assets/js/test.js?v=15"></script>
<script src="/assets/js/test.js?v=16"></script>
<script src="/assets/js/test.js?v=17"></script>
<script src="/assets/js/test.js?v=18"></script>
<script src="/assets/js/test.js?v=19"></script>
<script src="/assets/js/test.js?v=20"></script>
<script src="/assets/js/test.js?v=21"></script>
<script src="/assets/js/test.js?v=22"></script>
<script src="/assets/js/test.js?v=23"></script>
<script src="/assets/js/test.js?v=24"></script>
<script src="/assets/js/test.js?v=25"></script>
</html>
然后我做了同样的事情,但添加了 async 属性,以防 Chrome 在处理 Javascript 时决定阻止下载:
<script src="/assets/js/test.js?v=01" async=""></script>
<script src="/assets/js/test.js?v=02" async=""></script>
....etc.
同样如此,但带有 defer 属性:
<script src="/assets/js/test.js?v=01" defer=""></script>
<script src="/assets/js/test.js?v=02" defer=""></script>
....etc.
/assets/js/test.js 文件为空。所以除了浏览器添加的那些之外,不会有执行延迟,也没有依赖。
我看到了一些有趣的结果!这都是使用 Chrome 60.0.3112.78 或 60.0.3112.101,我使用的是 Apache,但看到的结果与您在 Nginx 中看到的结果相同。
使用 HTTP/2 服务器,我们看到以下结果:
使用普通的script 标签,所有脚本都是并行加载的(但可能是按顺序执行的)。 HTTP/1.1 下没有 6 个连接限制:
使用 async script 标记,脚本以 6 个一组并行加载 - 正如您所指出的:
点击它们表明它们是通过 HTTP/2 下载的。
使用 defer script 标签,脚本与使用 async 标签的结果相同 - 一次限制为 6 次下载。
这没有意义 - Chrome 会限制您的 Javascript 下载,但前提是您使用异步或延迟来改善您的下载,以免阻塞渲染!
正如 sbordet 所说,视口中的图像不会发生同样的情况 - 所以多路复用确实可以在 Chrome 上工作,它似乎对异步或延迟模式下的 Javascript 进行了不必要的限制。如果您考虑在 HTTP/2 下不再将脚本捆绑在一起,这是一个真正的限制,因为许多人建议您不再需要这样做。
不会同样发生在 Firefox 和 Edge 上。虽然它确实发生在 Opera(基于 Chromium 的浏览器)上。
所以这是个坏消息。好消息是他们“可能”已经修复了它。当我尝试 Chrome Canary (62.0.3190.0) 时,我无法重复这种行为。但是,当我将 Web Page Test 与 Canary 一起使用时(它在用户代理字符串中给出 62.0.3190.1,因此应该几乎相同)它 是 可重复的,所以不能 100% 确定他们在之后修复了这个问题所有...
已经向 Chrome 团队提出了一个错误,所以看看他们怎么说:https://bugs.chromium.org/p/chromium/issues/detail?id=757191
总而言之,服务器和客户端上的 HTTP/2 目前看起来确实有点不稳定,因为双方都在调整和调整他们的实现,以充分利用这个仍然相对较新的协议。尽管如此,令人惊讶的是,Chrome 受到了这一打击,因为 Google 以他们的 SDPY 实现(HTTP/2 主要基于该实现)开始了这一点,所以你会期望他们走在曲线的前面而不是落后......
** 更新**
Chrome 团队回来确认这是对 Chrome 中当前 HTTP/2 实现的限制。当 HTTP/2 允许同时调用许多资产时,他们会看到性能问题,因此将非关键项目(包括异步/延迟和视口中不可见的项目)限制为 HTTP/1.1 限制为 6。
尽管 HTTP/2 具有在请求发送后对其进行优先排序的概念,但性能问题在它们被优先处理和发送之前就已经被发现(例如检查缓存、cookie 等),因此 HTTP/2 优先排序没有帮助在这里。
他们希望在未来改进这一点。
所以我猜我是对的,这是一个实现问题,因为我们已经习惯了新的 HTTP/2 世界并且必须为此优化我们的浏览器和服务器!