基于模块的开发在可缓存性、 帮助您减少需要向用户配送的字节数。 更细粒度的代码也有助于故事加载, 确定应用中关键代码的优先级。
不过,模块依赖关系会导致加载问题,因为浏览器需要 在模块确定其依赖项之前,先等待模块加载。单程 方法是预加载依赖项 文件,并可使连接保持忙碌状态。
<link rel="preload">
<link rel="preload">
是一种提前以声明方式请求资源的方法,
从而避免浏览器需要这些标记
<head>
<link rel="preload" as="style" href="critical-styles.css">
<link rel="preload" as="font" crossorigin type="font/woff2" href="myfont.woff2">
</head>
浏览器支持
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
这对字体等资源特别有用,因为资源通常处于隐藏状态 (有时会有好几级深度)在这种情况下 就必须等待多次往返才会发现 当它本来可以利用该时间开始下载时,会提取大型字体文件 并充分利用全部连接带宽
<link rel="preload">
及其 HTTP 标头等效项提供了一种简单的声明式
让浏览器立刻知道需要的关键文件
作为当前导航的一部分当浏览器发现预加载内容时,会启动一个高
这样,当资源真正需要时,资源就会
已提取或已部分提取到该位置。但不适用于模块。
为什么 <link rel="preload">
不适用于模块?
这正是棘手的地方。我们提供多种凭据模式, 它们必须匹配才能获得缓存命中,否则 提取该资源两次。毋庸置疑,双重提取是非常糟糕的 会浪费用户的带宽,导致他们无端等待更长时间。
对于 <script>
和 <link>
标记,您可以使用 crossorigin
设置凭据模式
属性。不过,结果是没有指定字段的 <script type="module">
crossorigin
属性指示 omit
的凭据模式,该模式不存在
价格为 <link rel="preload">
。这意味着
将 <script>
和 <link>
中的 crossorigin
属性都更改为一
但如果您的目标对象是其他值,
依赖于其他模块的依赖项。
此外,获取文件只是实际运行代码的第一步。
首先,浏览器必须解析并编译该文件。理想情况下
也应提前进行此操作
运行状态。不过,V8(Chrome 的 JavaScript 引擎)可解析和编译模块,
与其他 JavaScript 不同。<link rel="preload">
不可以
提供任何方式来指明正在加载的文件是一个模块,因此所有浏览器
加载文件并将其放入缓存使用
<script type="module">
标记(或由其他模块加载),则浏览器会解析
并将代码编译为 JavaScript 模块。
那么,对于模块,<link rel="modulepreload">
是否只是 <link rel="preload">
?
简而言之,是的。通过为预加载模块使用特定的 link
类型,我们能够
编写简单的 HTML 时,无需担心我们使用的是何种凭据模式。通过
使用默认设置。
<head>
<link rel="modulepreload" href="super-critical-stuff.mjs">
</head>
[...]
<script type="module" src="super-critical-stuff.mjs">
由于浏览器现在知道您要预加载的是模块,因此 加载完成后立即解析和编译模块,而不是等待 直到应用尝试运行为止
浏览器支持
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
那么模块的依赖项?
真有趣,因为你应该这么问!确实有一个本文未涉及的内容:递归。
实际上,<link rel="modulepreload">
规范允许视需要加载,而不仅仅是
请求的模块及其所有的依赖关系树。浏览器不必
但可以。
那么,预加载模块的最佳跨浏览器解决方案是什么? 因为您需要完整的依赖关系树来运行应用?
选择以递归方式预加载依赖项的浏览器应具有强大的去重功能 模块,因此一般而言,最佳实践是声明模块和扁平列表 并确保浏览器不会重复提取同一个模块。
<head>
<!-- dog.js imports dog-head.js, which in turn imports
dog-head-mouth.js, which imports dog-head-mouth-tongue.js. -->
<link rel="modulepreload" href="dog-head-mouth-tongue.mjs">
<link rel="modulepreload" href="dog-head-mouth.mjs">
<link rel="modulepreload" href="dog-head.mjs">
<link rel="modulepreload" href="dog.mjs">
</head>
预加载模块是否有助于提升性能?
预加载可以告知浏览器 因此它需要获取数据,以免在如此长的往返期间无任何操作 如果您正在测试模块并因深度优化而遇到性能问题 依赖项树,那么创建一个扁平的预加载列表肯定会有所帮助。
尽管如此,模块性能仍在开发中,因此请确保 您可以使用开发者工具来仔细观察应用中发生的情况 在此期间,不妨考虑将您的应用捆绑成几个块。这里有很多 但 Chrome 中正在进行的模块工作 因此,我们离提供 捆绑工人赚取丰厚的休息时间!