1.减少HTTP请求

一个完整的 HTTP 请求需要经历 DNS 查找,TCP 握手,浏览器发出 HTTP 请求,服务器接收请求,服务器处理请求并发回响应,浏览器接收响应等过程。建立连接和下载数据都需要时间,应尽量将多个小文件合并为一个大文件,从而减少 HTTP 请求次数。

HTTP2.0的多路复用和服务器推送功能解决了HTTP多次请求的问题,HTTP2.0逐渐普及了,这个方法也不那么侧重了。

2.将 CSS 放在文件头部,JavaScript 文件放在底部

所有放在 head 标签里的 CSS 和 JS 文件都会堵塞渲染(CSS 不会阻塞 DOM 解析)。如果这些 CSS 和 JS 需要加载和解析很久的话,那么页面就空白了。所以 JS 文件要放在底部,等 HTML 解析完了再加载 JS 文件。

那为什么 CSS 文件还要放在头部呢?

因为先加载 HTML 再加载 CSS,会让用户第一时间看到的页面是没有样式的、“丑陋”的,为了避免这种情况发生,就要将 CSS 文件放在头部了。

另外,JS 文件也不是不可以放在头部,只要给 script 标签加上 defer 属性就可以了,异步下载,延迟执行。 script 标签加上 async 属性可能会阻塞渲染。关于defer和async属性的差别可以看这篇:图解 script 标签中的 async 和 defer 属性

3.减少重绘重排

浏览器渲染过程

  1. 解析HTML生成DOM树。

  2. 解析CSS生成CSSOM规则树。

  3. 解析JS,操作 DOM 树和 CSSOM 规则树。

  4. 将DOM树与CSSOM规则树合并在一起生成渲染树。

  5. 遍历渲染树开始布局,计算每个节点的位置大小信息。

  6. 浏览器将所有图层的数据发送给GPU,GPU将图层合成并显示在屏幕上。

    image.png

重排
元素位置和尺寸发生改变、DOM元素的增删、添加行内样式、浏览器窗口发生改变、页面首次渲染,元素相对于文档定位改变时会导致浏览器重新生成渲染树,这个过程叫重排。

重绘
当重新生成渲染树后,会将渲染树每个节点绘制到屏幕,这个过程叫重绘。颜色改变、背景图片改变,只要不影响元素相对于浏览器文档位置的改变,就只导致重绘。

如何减少重排重绘?

  • 减少DOM操作 (修改DOM节点的多条语句合并成一条语句来执行:事件代理)
  • 避免使用行内样式/样式集中改变
  • 使用 absolute 或 fixed 脱离文档流
  • 优化动画 (将动画效果应用到脱离文档流的元素上;使用css过渡/动画属性;画布等)

4.图片优化

图片延迟加载

在页面中,先不给图片设置路径,只有当图片出现在浏览器的可视区域时,才去加载真正的图片,这就是延迟加载,即懒加载。
懒加载相当于是把代码在一些逻辑断点处分离开,需要加载时才加载。这样加快了应用的初始加载速度,减轻了它的总体体积,因为某些代码块可能永远不会被加载。

 

使用字体图标 iconfont 代替图片图标

字体图标就是将图标制作成一个字体,使用时就跟字体一样,可以设置属性,例如 font-size、color 等等,非常方便。并且字体图标是矢量图,不会失真。并且生成的文件特别小,很好用。比如阿里的图标库。

使用精灵图

所谓精灵图就是把很多的小图片合并到一张较大的图片里,所以在首次加载页面的时候,就不用加载过多的小图片,只需要加载大的精灵图,这样在一定程度上减少了页面的加载速度,也一定程度上缓解了服务器的压力。
使用:将精灵图设为一个大背景,然后通过background-position来移动背景图,从而显示出我们想要显示出来的部分。
缺点:图片的背景需要详细测量而得出来的,当需要改动页面,会很麻烦。

尽可能利用 CSS3 效果代替图片

有很多图片使用 CSS 效果(渐变、阴影等)就能画出来,这种情况选择 CSS3 效果更好,动画也可以使用css过渡/动画属性/画布等方法来优化,因为代码大小通常是图片大小的几分之一甚至几十分之一。

使用 webp 格式的图片

WebP 的优势体现在它具有更优的图像数据压缩算法,能带来更小的图片体积,而且拥有肉眼识别无差异的图像质量;同时具备了无损和有损的压缩模式、Alpha 透明以及动画的特性,在 JPEG 和 PNG 上的转化效果都相当优秀、稳定和统一。

WebP优势可查看文档:WebP 相对于 PNG、JPG 有什么优势?

5.压缩文件

压缩文件可以减少文件下载时间,让用户体验性更好。

gzip 是目前最流行和最有效的压缩方法,可以通过向 HTTP 请求头中的 Accept-Encoding 头添加 gzip 标识来开启这一功能。

在 webpack 可以使用如下插件进行压缩:

  • JavaScript:UglifyPlugin
  • CSS :MiniCssExtractPlugin
  • HTML:HtmlWebpackPlugin

6.善用缓存,不重复加载相同资源

为了避免用户每次访问网站都得请求文件,我们可以通过添加 Expires 或 max-age 来控制这一行为。Expires 设置了一个时间,只要在这个时间之前,浏览器都不会请求文件,而是直接使用缓存。而 max-age 是一个相对时间,建议使用 max-age 代替 Expires 。
这里又涉及HTTP缓存的知识,可以看这篇: 一文读懂http缓存

7.使用事件代理

事件代理(委托):把原本需要绑定在子元素的响应事件委托给父元素,让父元素担任事件监听的职务。原理是DOM元素的事件冒泡。 优点:节省内存空间,减少事件注册(比如鼠标事件和键盘事件,ul代理所有li的click事件,新增元素时无需再次对其进行事件绑定)。

8.静态资源使用CDN

内容分发网络(CDN)是一组分布在多个不同地理位置的web服务器。这些服务器存储着数据的副本,因此服务器会根据哪些服务器离用户距离最近来满足数据的请求。 CDN的两个核心点:

  • 缓存:就是指我们把资源复制一份到CDN服务器的这个过程
  • 回溯:指CDN发现自己没有这个资源(一般是缓存的数据过期了),转头向根服务器(或者上级服务器)去要资源的这个过程

 

9.使用服务器端渲染

客户端渲染: 获取HTML文件,根据需要下载 JavaScriptCSS文件,运行文件,生成 DOM,再渲染。

服务端渲染:服务端返回 HTML 文件,客户端只需解析 HTML

  • 优点:首屏渲染快,SEO好。
  • 缺点:配置麻烦,增加了服务器的计算压力

区别:客户端渲染的网站是直接返回HTML文件,而服务端渲染的网站是渲染完页面再返回这个HTML文件。VueSSR就是服务端渲染。

题外话
单页面应用(SPA)就是客户端渲染,页面加载完后不会在重新加载或跳转,取而代之是利用JS动态变换来响应用户的操作。
SPA具有良好的交互体验,没有页面的切换,不会出现"白屏","闪烁"现象;良好的前后端工作分离模式;并且减轻服务器的压力。但首屏加载慢,不利于SEO(搜索引擎优化),不适合开发大型项目。

可以看出,各有各的好处和缺点。服务端渲染配置麻烦,会加重服务器的压力,其实实际项目中的话,可以异步加载组件,或者使用vue-router懒加载组件。

10.webpack按需加载代码——Tree-Shaking

懒加载或者按需加载,是一种很好的优化网页或应用的方式。这种方式实际上是先把你的代码在一些逻辑断点处分离开,然后在一些代码块中完成某些操作后,立即引用或即将引用另外一些新的代码块。这样加快了应用的初始加载速度,减轻了它的总体体积,因为某些代码块可能永远不会被加载。

在 webpack 项目中,有一个入口文件,相当于一棵树的主干,入口文件有很多依赖的模块,相当于树枝。实际情况中,虽然依赖了某个模块,但其实只使用其中的某些功能。通过 tree-shaking,将没有使用的模块摇掉,这样来达到删除无用代码的目的。(ES6的import动态引入组件实现按需加载)

 

11.使用 Web Workers

Web Worker 使用其他工作线程从而独立于主线程之外,它可以执行任务而不干扰用户界面。一个 worker 可以将消息发送到创建它的 JavaScript 代码, 通过将消息发送到该代码指定的事件处理程序(反之亦然)。

Web Worker 适用于那些处理纯数据,或者与浏览器 UI 无关的长时间运行脚本。