首先我们应该明确一点
优化关乎的是速度和满意度
从用户体验角度, 我们更希望前端网页可以快速加载
从开发体验角度, 我们可能更希望是快速,简洁,规范的
首先我们要明确一个问题: 浏览器都做了什么
当我们打开一个简单的网页的时候
<!DOCTYPE html>
<html>
<head>
<title>The "Click the button" page</title>
<meta charset="UTF-8">
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<h1>
Click the button.
</h1>
<button type="button">Click me</button>
<script>
var button = document.querySelector("button");
button.style.fontWeight = "bold";
button.addEventListener("click", function () {
alert("Well done.");
});
</script>
</body>
</html>
浏览器是如何渲染网页页面的
1 使用 HTML创建文档对象模型也就是我们常说的DOM
2 使用CSS创建CSS对象模型(CSSOM)
3 基于DOM和CSSOM执行脚本(scripts)
4 合并DOM和CSSOM形成渲染树(Render Tree)
5 使用渲染树布局(Layout)所有元素
6 渲染所有元素
步骤一 HTML
浏览器从上到下读取标签,把他们分解成节点,从而创建DOM。
HTML的加载优化的策略
1 样式在顶部,脚本在底部
总体的思路就是尽可能早的加载样式,尽可能晚的加载脚本,原因是脚本执行之前,我们需要HTML和CSS解析完成,因此,样式尽可能的往顶部放,当底部脚本开始执行之前,样式有足够的时间完成计算。。
关于优化
1 最小化和压缩
方法可用于所有内容,包括HTML,CSS,图片和其他资源。
最小化是移除所有多余的字符,包括空格,注释,多余的分号,等等。。
压缩包括GZIP压缩,大大压缩下载文件的大小
两种方法都用的情况下,资源加载量较少了80%到90%
2 无障碍
不去提升页面的下载速度,但会大大提升残障人士的满意度,给元素加上aria标签,图片提供alt文本,
使用诸如wave的工具来鉴别哪些地方可以提高可访问性。。
步骤二 CSS
当浏览器发现任何节点相关的样式时,比如:外部,内部,或者行内样式,立即停止渲染DOM,并利用这些节点创建CSSOM,这就是CSS阻塞渲染的由来,这里是不同类型样式的优缺点。。
//外部样式
<link rel="stylesheet" href="styles.css">
// 内部样式
<style>
h1 {
font-size: 18px;
}
</style>
// 行内样式
<button style="background-color: blue;">Click me</button>
CSSOM节点创建与DOM节点创建类似,随后两者合并
CSSOM的构建会阻塞页面的渲染,因此我们想尽可能早的加载样式。。
关于其优化策略
使用media属性
media属性指定加载样式的条件,比如:符合最大和最小分辨率?还是面向屏幕阅读器? 参考media
延迟加载CSS
有些样式,比如说:首屏一下的,或者不那么重要的,可以等待首屏最有价值的内容渲染完成在加载,可以使用脚本等待页面加载,然后在插入样式。
giftofspeed link-in-body 这是例子
只加载需要的样式
可以使用uncss的工具来测试不需要的代码
步骤三 JavaScript
浏览器不断构建DOM/CSSOM节点,直到发现外部或者行内的脚本。
由于脚本可能需要访问或操作之前的HTML样式,我们必须等待他们构建完成。
因为浏览器必须停止解析节点,完成构建cssom,执行脚本,然后再继续,这就是js被称为解析器阻塞的原因。。。。
所以脚本只能等待先前的css节点构建完成。
优化策略
异步加载脚本
脚本添加async属性,可以通知浏览器不要阻塞其余页面的加载,下载脚本处于较低的优先级,一旦下载完成就可以执行。。
async适用于不影响DOM或者CSSOM的脚本,对一些跟我们的代码无关的,不影响用户体验的外部脚本尤其适用,比如:分析统计脚本。
defer跟async非常相似,不会阻塞页面加载,但是会等到HTML完成解析后在执行。
使用defer策略的javascript,也可以适用addEventListener,了解更多点击打开链接
操作之前克隆节点
多次操作DOM时可以尝试,首先克隆整个节点更加高效,操作克隆后的节点,然后替换先前的节点,避免了多次重绘,降低了cpu和内存的消耗,同事也避免了不必要的页面闪烁。
需要注意的是克隆节点的时候,并没有克隆事件监听。
步骤四 渲染树
一旦所有节点已被解析,DOM和cssom准备合并,浏览器便会构建渲染树,如果我们把节点想象成单词,那么对象模型就是句子,渲染树便是整个页面。。
步骤五 布局
布局阶段需要确定页面上所有元素的大小和位置。
步骤六 渲染
最终的渲染阶段,会真正地光栅化屏幕上的像素,把页面呈现给用户。
整个过程耗时1秒或十分之一秒,我们的任务是让它更快。
如果js事件改变了页面某个部分,便会引起渲染树的重回,并且迫使布局和渲染过程再次进行