性能优化——从浏览器输入url开始说起

884 阅读5分钟

从输入url开始

  1. 判断是否命中缓存,如果命中缓存,直接由缓存提供资源,否则继续下面的步骤
  2. DNS查询:解析输入url对应的IP地址
  3. 根据IP建立TCP连接,过程中有3次握手
  4. HTTP向服务器发起请求
  5. 服务器处理请求,协商缓存——如果请求头有相应的信息,就可以不需要从服务器请求资源,直接从浏览器读取缓存的HTML,跳过第6步
  6. 服务器返回HTML响应给浏览器
  7. 浏览器解析HTML
  8. 对HTML页面引用的所有资源包括js,css,图片等等,浏览器都发送GET请求,又重复上面的过程
  • 优化:减少加载需要建立连接的次数,启用http1.1默认开启的keep-alive长连接,短连接就是每次请求都要重新建立TCP连接,请求完成断开TCP连接,长连接同一个客户端socket向同一socket的后续请求都复用同一个TCP连接。

页面加载的性能优化

  1. 虽然长连接可以使一个TCP连接请求多个资源,但是我们请求的资源往往是有关联的,比如要先请求完1.css 再请求1.js

  2. 浏览器一般会建立多个TCP连接,并行请求资源,从而加快整体的速度,但是并行请求的数量是有限制的

针对以上两点,我们还是需要去做一些优化。

  1. 减少HTTP请求的次数,所以就有了代码合并,雪碧图,将图片转为base64写入其他文件

  2. 使用HTTP 2,提供了多路复用的功能,所有资源都可以通过一个TCP连接不阻塞的并行传输,就不需要再做减少HTTP请求次数的优化了。

  3. 减少请求资源的大小:开启Gzip可以大幅减少资源体积,分割代码并启用路由(组件)懒加载,优化首屏加载的性能,使用合理的图片大小和格式比如说谷歌开发的图片格式WebP,或者直接用字体图标代替图片,字体图标不仅体积小,而且可以任意变化大小不会模糊,还可以任意变化颜色,使用非常灵活

  4. 缓存,不需要接受数据的传输,直接使用浏览器的本地缓存,分为两种:强缓存和协商缓存,一般是由上一次请求服务器返回的响应头控制。

    • 强缓存:不会向服务器发送请求,Cache-control或者Expires判断,如果命中,就返回状态码200;
    • 如果不命中则是判断是否协商缓存:向服务器发送验证请求,如果请求头有If-Modified-Since,服务器返回Last-Modified,如果两个相同则返回状态码304;如果发送的请求头有If-None-Match,服务器返回ETag,比较两者,如果相同则返回状态码304

需要注意的是强缓存则不会与服务器有任何交互,所以服务器更新了资源,浏览器也无法得知,如果每次请求都使用协商缓存,每次都要向服务器发送验证请求,又多做了无用功,所以我们应该尽可能的使用强缓存,但是在更新版本之后让缓存失效,所以在更新版本的时候直接修改资源文件名就可以实现了,然后webpack可以让我们在打包的时候自动给文件名加上哈希值。

页面渲染过程

  1. 解析HTML,生成DOM树
  2. 解析CSS,生成CSSOM树
  3. 将DOM树和CSSOM树合成渲染树,确定每个元素运用哪个CSS规则
  4. 根据渲染树,进行页面的布局,计算每个节点的大小和位置
  5. 在页面上绘制各个节点

页面渲染的性能优化

问题:

  1. css是阻塞渲染的资源,直到CSSOM构建完毕,不会渲染任何已经处理的内容
  2. 在HTML的解析过程中如果遇到scirpt标签,会停止DOM树的构建,知道执行完毕,但仍会识别后面的资源并进行预加载,JavaScript可以查询和修改CSSOM和DOM
  3. 回流还有重绘导致渲染树重新生成
    • 回流会重新计算布局,通常是由元素的结构,增删,位置,尺寸变化引起的;还有在js中读取元素的offset,client,getCom putedStyle也会引起,由CPU处理
    • 重绘:元素的视觉表现变化会引起,比如颜色,背景的改变,由GPU处理
    • 如果回流,则一定会引起重绘,并且CPU的处理效率不如GPU,所以更注重减少回流

针对以上问题可以做的优化:

dom:

  • 减少dom元素的数量,降低DOM的深度,减少生成DOM树和渲染树的构建成本,尽量避免塞进去div元素只为了实现布局,可以用伪元素的就用伪元素

js:

  • 将js放在body底部
  • 减少以及合并DOM操作,使用DocumentFragment进行DOM的离线更新

css:

  • 放在head中,避免html渲染完成后,又重新结合CSSOM树,引起页面闪烁
  • 降低css的层级和选择器的复杂度
  • 使用更高性能的css样式,比如用flex布局代替float布局
  • 合理使用脱离文档流的样式,比如absolute,fiexd,减少引发回流
  • 优先使用transform,opacity等属性来实现动画,可以跳过布局和绘制的过程,计算样式之后直接进行渲染层合并