Web性能优化始终是当务之急,尤其是在竞争如此激烈的现在。众所周知是,更快的网站下载速度已显示出可以提高访问者的保留率和忠诚度以及用户满意度,尤其是对于网络速度较慢的用户和移动设备上的用户而言!
常用web优化方法
1. HTTP请求减少
一次完整的请求都需要经过队列等待、 DNS寻址、与服务器建立连接、发送请求、等待服务器响应、下载数据这样一个 “漫长” 而复杂的过程。通常,网页请求的HTTP越多,加载速度就越慢。因为浏览器限制了单个域名下同时一定数量的同时连接数(一般为6-12个)。为避免瓶颈,使用资源合并、雪碧图等以减少了单个页面的请求数量。从而减少HTTP请求和加载网页所需的往返次数。减少HTTP请求是最重要的优化技术,其影响最大。
2.文件压缩
Web页面是由HTML、CSS和JavaScript等代码文件构成的。随着网页复杂程度的提高,其代码文件以及随后的加载时间也随之增加。文件压缩可以将代码文件减少多达80%,从而提高站点响应速度。通常使用webpack、gulp或grunt来压缩web代码, 使用tinypng来压缩图片。
3. 浏览器缓存
缓存优化可减少服务器负载,带宽使用量和延迟,如果允许浏览器缓存您的站点文件(外部样式表,JavaScript文件,图像等)意味着不需要每次用户请求站点上的网页时都下载文件。这可以加快用户导航到另一个网页时的体验,因为不需要重新下载诸如样式表、图片和字体之类的内容,因为它们已经存储在用户的浏览器缓存中。
那么,我们如何允许浏览器缓存文件?
当浏览器从我们的Web服务器请求文件时,服务器将执行的操作之一就是发送文件的HTTP标头。文件的HTTP标头包含有关所请求文件的元数据,以及有关浏览器应如何处理文件的说明。
我们可以指定的标准HTTP标头字段之一是Cache-Control
来设置缓存方式,Cache-Control
允许我们定义我们希望浏览器缓存文件的方式。我们可以使用Cache-Control标头字段来告诉浏览器是否应该缓存文件,以及应该缓存文件多长时间。
)
您可以在DevTools 的Response Headers中看到Cache-control字段
Cache-Control: max-age=2592000
顺便说一句,max-age以秒为单位指定。2,592,000秒= 30天。
对于要缓存文件的确切时间,没有具体的规定,但是最佳实践是将文件缓存的时间尽可能长。
缓存持续时间取决于您更新站点文件的频率以及要缓存的文件类型。例如,您可以max-age为不经常更改的文件(例如网站的LOGO,JS文件和CSS文件)设置更长的时间。
文件类型 | 缓存持续时间 |
---|---|
CSS | 1年 |
JavaScript | 1年 |
图片(例如PNG,JPG,GIF) | 1个月 |
HTML | 不使用缓存 |
对于SVG文件,我们可以使用svg-sprite-loader
来创建一个属于自己的图标库:
)
4. 开启GZIP
虽然开启GZIP压缩可以很大程度上压缩资源文件,但是也有一些需要注意的地方:
-
较旧的浏览器:某些浏览器可能仍无法处理压缩内容(它们说可以接受,但实际上不能)。
-
已经压缩的内容:大多数图像,音乐和视频已经被压缩。不要浪费时间再次压缩它们。实际上,您可能只需要压缩“三大文件”(HTML,CSS和JavaScript)。
-
CPU负载:动态压缩内容会占用CPU时间并节省带宽。通常鉴于压缩速度和CPU的性能限制,通常将压缩等级设置为6(随着压缩级别的升高,压缩比有所提高,但到了级别6后,很难再提高,并且压缩时间和压缩比例成正相关)。
如果使用Nodejs作为服务器,可以使用compression
插件来开启gzip。如果使用nginx作为静态资源服务器,开启gzip方法如下:
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.0;
gzip_comp_level 6;
gzip_types text/plain application/javascript application/x-javascript text/javascript text/xml text/css image/jpeg image/jpg image/gif image/svg image/png;
gzip_disable "MSIE [1-6]\.";
gzip_vary on;
5. 预加载
DNS预取-DNS Prefetch
这会通知客户端,我们以后需要通过特定的URL来获取资产,以便浏览器可以尽快解析DNS。假设我们需要URL中的资源如图像或音频等文件需要从www.gogoing.site网站下下载。在HTML的<head>中,加入以下代码:
<link rel="dns-prefetch" href="//www.gogoing.site">
然后,当我们请求文件时,我们将不再需要等待DNS查找。Chrome一直在做类似的事情。如果您仅在URL栏中键入域名的一小部分,它将自动预解析DNS(有时甚至预渲染页面),从而节省了每个请求至关重要的毫秒数。
资源预取-Prefetch
<link rel="prefetch" href="//cloud.gogoing.site/files/2020-08-07/95baf0bf-5878-4723-8ea0-159822f693ed.jpg">
Prefetch和DNS Prefetch相同。Prefetch应主要用于预加载静态资源,例如图像,CSS和JavaScript文件。整个文件将下载并保存在浏览器缓存中。也可以预取HTML文档。
但是,您不能依赖正在下载的资源。浏览器会在处于空闲状态时并且没有其他要执行的任务下载资源文件。如果用户的网络连接较慢,它也将完全忽略大文件。
子资源- subresource
<link rel="subresource" href="//cloud.gogoing.site/files/2020-08-07/95baf0bf-5878-4723-8ea0-159822f693ed.jpg">
subresource与Prefetch相同。都是从服务器预下载指定的文件,并将其存储在浏览器的缓存中。但是不同的是,根据Chromium文档,它的工作方式如下:
LINK rel=“subresource”提供了一种新的链接关系类型,其语义与LINK rel="prefetch"不同。尽管rel="prefetch"提供了低优先级的资源下载,以供后续页面使用,而rel="subresource"则允许及早加载当前页面中的资源。
因此,如果当前页面需要该资产,或者尽快需要该资产,则最好使用它subresource,否则请使用prefetch。
预渲染-Prerender
预渲染功能是此处介绍的最强大的技术。从根本上确保具有所有必要静态资源的URL在后台完全加载和设置。您可以想象它是在新选项卡中预先打开URL,但在用户实际调出页面之前它一直处于隐藏状态。并且所有在实际页面下载期间发生的活动都将在后台进行。
但是由于兼容性问题,一般情况下,我们都会同时使用Prefetch和Prerender来预加载HTML文档。
任何丢失的文件都会产生HTTP 404 错误。如果请求一个不存在的脚本文件,因为浏览器在请求脚本文件的时候,即便是返回404,它也会尝试去按照Javascript的方式解析响应中的内容。这无疑会增加很多处理的时间。
6. 重绘和回流
在了解重绘和回流之前,我们先回顾一下浏览器的工作原理:
- 浏览器解析HTML源代码,并构造一个DOM树,其中每个HTML标签在树中都有一个对应的节点,标签之间的文本块也会生成一个文本节点。DOM树中的根节点是documentElement(<html>标记)
- 浏览器解析CSS代码:基础规则在User-Agent样式表(浏览器默认设置)中,然后可能有用户样式表,作者样式表,外部样式,导入样式,内联样式以及最终样式被编码为styleHTML标签的属性
- 接下来是构造渲染树(render tree)。渲染树有点像DOM树,但不完全匹配。渲染树会获取样式信息,因此,如果您将元素隐藏
display: none
,则它将不会出现在渲染树中。其他不可见元素(例如,head以及其中的所有元素)也是如此。另一方面,例如在渲染树状文本节点中可能存在* 用多个节点表示的DOM元素。渲染树中的节点称为box(CSS box 中的盒模型),每个节点都有CSS框属性-宽度,高度,边框,边距等 - 构造渲染树后,对于每个visible节点,匹配合适的节点CSSOM rules并应用它们,然后浏览器在屏幕上绘制渲染树节点。
)
重绘-repaint
由于节点属性的更改或样式更改(例如更改opacity,color,background-color,visibility),因此需要更新屏幕的某些部分。此屏幕更新称为重绘(repaint)。
回流-reflow
渲染树的一部分(或整个树)需要重新计算,包括元素的位置、宽高度以及边框等几何形状以及所有受影响的其他元素的位置都会由浏览器重新绘制,此过程称为回流。更改单个元素会影响所有的子元素,祖先元素和兄弟元素。
回流一定会导致重绘。
通常情况下,以下情况会导致回流:
- 激活伪类,如:hover
- 内容输入,如input输入
- 添加、删除样式表
- 添加、删除、更新DOM节点
- 使用offsetWidth和offsetHeight
- 为DOM节点设置动画以及使用JS来块操作DOM节点
- 使用display: none(重绘和回流)或visibility: hidden(仅重绘,因为不会没有位置发生更改且不会影响后面节点的显示)隐藏DOM节点
- 用户操作,如调整窗口大小,更改字体大小或滚动
如何减少重绘和回流
- 避免使用表格进行布局
- 通过为容器设置固定高度来限制受影响的元素
- 使用offsetWidth和offsetHeight时, 先将其缓存到本地变量中,不要每次直接从元素属性中读取
- 尽量通过添加/修改className来控制节点样式,且减少CSS规则层级以及使用复杂的CSS选择器
- 批量更新DOM,且减少DOM深度。使用
documentFragment
来操作DOM变化数据。更新/克隆/替换节点时,先将节点样式设置为display: none
, 替换完成后再移出display: none
样式(总共2个回流和2个重绘),
7. 避免301重定向
重定向是性能的杀手,应该尽可能避免使用它们。重定向将产生额外的往返时间(RTT),因此在浏览器甚至开始加载其他资源之前,加载初始HTML文档所需的时间将迅速增加一倍。
8. 浏览器存储
使用浏览器存储(localStorage或sessionStorage)来存储网站中使用的不可变数据以保证页面的加载速度和减少不必要的请求。在某些情况下(如商城),还可以保存首页数据,以保证首页的快速加载和减少白屏时间。