高级前端开发人员必备技能 - 第 2 部分
这篇文章是《高级前端开发人员,面试要点 - 第 1 部分》的续篇,如果你还没有读过,我强烈建议你先阅读一下我详细解释 CRP 的文章。
优化关键渲染路径对于网站的性能至关重要,请始终牢记以下规则
你无法优化无法衡量的东西
1.DOM优化
您应该尽可能快地传输 HTML,我们可以通过这些步骤的最小化、压缩和缓存 HTML 来实现这一点。
你认为页面会在 CRP 的哪个阶段渲染?
它会在渲染树构建时渲染,也就是 CSSOM 构建完成后,这会是渲染阻塞步骤,所以优化 CSSOM 至关重要。
2.CSSOM优化
由于 CSS 是一种渲染阻塞资源,因此请始终保持 CSS 精简,并尽快交付,我们可以使用媒体类型和查询来解除渲染阻塞
如果我们有一些 CSS 样式仅在特定条件下使用,例如,当页面被打印或投影到大显示器上时,但您正在移动设备上查看,那么我们可以阻止在未使用的资源上进行渲染。
CSSmedia types
允许media queries
我们解决这些用例,在下面的例子中,如果我们为不同的用例维护一个单独的样式表,例如:我们可能需要为打印或响应式网站应用某些样式,我们可以提到特定的宽度,在这种情况下只需要导入样式表
<link href="style.css" rel="stylesheet">
<link href="print.css" rel="stylesheet" media="print">
<link href="other.css" rel="stylesheet" media="(min-width: 40em)">
在声明样式表资产时,请密切关注媒体类型和查询;它们会极大地影响关键渲染路径的性能
解释:
<link href="style.css" rel="stylesheet">
<link href="style.css" rel="stylesheet" media="all">
<link href="portrait.css" rel="stylesheet" media="orientation:portrait">
<link href="print.css" rel="stylesheet" media="print">
- 第一个声明是渲染阻塞并在所有条件下匹配。
- 第二个声明同样会阻塞渲染:“all”是默认类型,所以如果你没有指定任何类型,它会被隐式设置为“all”。因此,第一个和第二个声明实际上是等效的。
- 第三个声明包含一个动态媒体查询,它会在页面加载时进行评估。根据页面加载时设备的方向,portrait.css 可能会或可能不会阻塞渲染。
- 最后的声明仅在打印页面时应用,因此当页面首次在浏览器中加载时它不会阻止渲染。
避免 CSS 导入
CSS import ( @import
) 指令允许一个样式表从另一个样式表文件导入规则。但是,请避免使用这些指令,因为它们会在关键路径中引入额外的往返:只有在 @import
接收并解析包含规则本身的 CSS 样式表后,才会发现导入的 CSS 资源。
将 CSS 放在文档头中
尽早在 HTML 文档中指定所有 CSS 资源,以便浏览器能够发现 <link>
标签并尽快发送 CSS 请求。
3. JS优化
JavaScript 允许我们修改页面的几乎每个方面:内容、样式以及页面对用户交互的响应。JavaScript 也可能阻止 DOM 构建并延迟页面渲染。为了获得最佳性能,请将 JavaScript 设置为异步,并从关键渲染路径中移除任何不必要的 JavaScript。
默认情况下,JavaScript 的执行是“解析器阻塞”的:当浏览器遇到文档中的脚本时,它必须暂停 DOM 构建,将控制权移交给 JavaScript 运行时,并让脚本执行后再继续进行 DOM 构建。
问题:
让我们来看下面的例子,其中有一个样式表以及修改<p>
标签的脚本,那么文本将呈现黑色还是红色,答案在于执行的顺序
- 页面请求 HTML,然后开始构建 DOM
- 然后会遇到样式,请求 CSS 资源,此时 CSS 并不知道脚本是否会修改 CSS,所以会等待 CSSOM 构建完成
- CSSOM 构建完成后,JS 将被执行并构建渲染树
CSS 会阻止脚本和页面渲染,因此优化 CSS 变得至关重要
解决方案 :
1.在这种情况下,所有 JS 代码可能不会修改 DOM,我们可以优化 JS,使其在 DOM 加载后加载它,如下所示
<script>
function loadFunction() {
alert("Window is loaded");
}
window.onload = loadFunction();
</script>
2. 解决这个问题的另一种方法是向标签添加async
属性script
,它做两件事 - 它不会阻止 DOM 构建和 CSSOM 构建,所以基本上它的作用是让 JS 不阻止 CRP
3. 您还defer
可以向脚本标签添加一个属性,该属性告诉解析器脚本应该等到文档加载完成后再执行
概括:
那么让我们看看有哪些选项可以优化 CRP
-
最小化、压缩和缓存 - HTML、CSS 和 JS
-
减少关键资源 - CSS 媒体查询,避免导入并使用关键内联 CSS、JS - 具有异步或延迟属性
-
缩短 CRP 长度,即减少获取资源的往返次数,有很多方法可以根据不同的通信协议进行优化,您可以参考这里
-
优化剩余关键资源的加载顺序:尽早下载所有关键资产,以缩短关键路径长度。
还有其他优化网站的方法,在我的下一篇文章中,我将讨论如何实现网站的快速加载时间
参考:
- https://developers.google.com/web/fundamentals/performance/critical-rendering-path
- https://classroom.udacity.com/courses/ud884