daily-plan icon indicating copy to clipboard operation
daily-plan copied to clipboard

2020-05-10 前端性能优化专栏(加载性能)

Open sl1673495 opened this issue 4 years ago • 7 comments

注意您发送的资源

  1. 由于 CSS 是一种阻塞渲染的资源,CSS 框架的开销可能导致渲染延迟严重。 您可以视情况移除不必要的开销,以加速渲染。

  2. 减少不必要的 js 库的引入。

  3. 迁移至 HTTP/2。 HTTP/2 可解决 HTTP/1.1 的许多固有性能问题,例如并发请求限制和缺乏标头压缩。

  4. 使用资源提示尽早下载资源。 rel=preload 是此类资源提示的一种,允许在浏览器发现关键资源之前提前提取这些资源。 如果能够谨慎使用,该资源会带来显著的积极效果

注意您发送的数据量

  1. 压缩源码

  2. 服务器配置 gzip

  3. 优化图像,oss 裁减,webp。

    • webp 兼容性:使用 picture 标签
     <picture class="picture">
       <source type="image/webp" srcset="image.webp">
         <img class="image" src="image.jpg">
      </picture>
    

sl1673495 avatar May 09 '20 06:05 sl1673495

RAIL

TL;DR

以用户为中心;最终目标不是让您的网站在任何特定设备上都能运行很快,而是使用户满意。 立即响应用户;在 100 毫秒以内确认用户输入。 设置动画或滚动时,在 10 毫秒以内生成帧。 最大程度增加主线程的空闲时间。 持续吸引用户;在 1000 毫秒以内呈现交互内容。

Response 响应 在 100 毫秒以内响应

响应:在 100 毫秒以内响应,对于需要超过 500 毫秒才能完成的操作,请始终提供反馈。

Animation 动画 在 10 毫秒内生成一帧

从纯粹的数学角度而言,每帧的预算约为 16 毫秒(1000 毫秒 / 60 帧 = 16.66 毫秒/帧)。 但因为浏览器需要花费时间将新帧绘制到屏幕上,只有 10 毫秒来执行代码。

image

Idle 空闲 最大程度增加空闲时间

利用空闲时间完成推迟的工作。例如,尽可能减少预加载数据,以便您的应用快速加载,并利用空闲时间加载剩余数据。

L 加载 在 1000 毫秒以内呈现内容

在 1 秒钟内加载您的网站。否则,用户的注意力会分散,他们处理任务的感觉会中断。

sl1673495 avatar May 09 '20 06:05 sl1673495

关键渲染路径

https://developers.google.com/web/fundamentals/performance/critical-rendering-path/constructing-the-object-model

浏览器渲染页面前需要先

  1. 处理 HTML 标记并构建 DOM 树。
  2. 处理 CSS 标记并构建 CSSOM 树。
  3. 将 DOM 与 CSSOM 合并成一个渲染树。
  4. 根据渲染树来布局,以计算每个节点的几何信息。
  5. 将各个节点绘制到屏幕上。

DOM树

image

CSSOM树

image

构建CSSOM的时间可以在performance面板里的Recalculate Style 这一项里观察到。

渲染树

浏览器将 DOM 和 CSSOM 合并成一个“渲染树”,网罗网页上所有可见的 DOM 内容,以及每个节点的所有 CSSOM 样式信息。

布局

有了渲染树,我们就可以进入“布局”阶段。为弄清每个对象在网页上的确切大小和位置,浏览器从渲染树的根节点开始进行遍历。

布局流程的输出是一个“盒模型”,它会精确地捕获每个元素在视口内的确切位置和尺寸:所有相对测量值都转换为屏幕上的绝对像素。

image

绘制

最后,既然我们知道了哪些节点可见、它们的计算样式以及几何信息,我们终于可以将这些信息传递给最后一个阶段:将渲染树中的每个节点转换成屏幕上的实际像素。这一步通常称为“绘制”或“栅格化”。

Chrome DevTools 可以帮助我们对上述所有三个阶段进行深入的了解。

image

  • “Layout”事件在时间线中捕获渲染树构建以及位置和尺寸计算。
  • 布局完成后,浏览器会立即发出“Paint Setup”和“Paint”事件,将渲染树转换成屏幕上的像素。

sl1673495 avatar May 09 '20 07:05 sl1673495

CSS阶段

默认情况下,CSS 被视为阻塞渲染的资源,这意味着浏览器将不会渲染任何已处理的内容,直至 CSSOM 构建完毕。请务必精简您的 CSS,尽快提供它,并利用媒体类型和查询来解除对渲染的阻塞。

TL;DR

  • 默认情况下,CSS 被视为阻塞渲染的资源。
  • 我们可以通过媒体类型和媒体查询将一些 CSS 资源标记为不阻塞渲染。
  • 浏览器会下载所有 CSS 资源,无论阻塞还是不阻塞。

sl1673495 avatar May 10 '20 11:05 sl1673495

JavaScript 阶段

JavaScript 也会阻止 DOM 构建和延缓网页渲染。 为了实现最佳性能,可以让您的 JavaScript 异步执行,并去除关键渲染路径中任何不必要的 JavaScript。

TL;DR

  • JavaScript 可以查询和修改 DOM 与 CSSOM。
  • JavaScript 执行会阻止 CSSOM。
  • 除非将 JavaScript 显式声明为异步,否则它会阻止构建 DOM。

关键点

  1. 浏览器将延迟脚本执行和 DOM 构建,直至其完成 CSSOM 的下载和构建。

  2. “优化关键渲染路径”在很大程度上是指了解和优化 HTML、CSS 和 JavaScript 之间的依赖关系谱。

  3. 向 script 标记添加异步关键字可以指示浏览器在等待脚本可用期间不阻止 DOM 构建,这样可以显著提升性能。(DOMContentLoaded事件明显提前了,它不再等待脚本下载并解析)

sl1673495 avatar May 10 '20 11:05 sl1673495

优化关键渲染路径

让我们定义一下用来描述关键渲染路径的词汇:

  • 关键资源: 可能阻止网页首次渲染的资源。
  • 关键路径长度: 获取所有关键资源所需的往返次数或总时间。
  • 关键字节: 实现网页首次渲染所需的总字节数,它是所有关键资源传送文件大小的总和。

关键路径长度并不一定取决于资源的数量,比如请求回来的 HTML 文件里解析到了一个 js 和一个 css 文件,那么这两个文件的请求会并行发出,其实它算作一次往返。

不推荐使用 @import 来引入 CSS 的原因之一也是因为如果它是出现在 CSS 文件中的话,它会在第一次路径请求回来 CSS 并 parse 后,再发起下载请求。这就形成了多余的一次路径。如果两个 CSS 文件都是始终需要的话,把他们平级的放在两个 link 标签里就好

优化关键渲染路径的常规步骤如下:

  • 对关键路径进行分析和特性描述:资源数、字节数、长度。
  • 最大限度减少关键资源的数量:删除它们,延迟它们的下载,将它们标记为异步等。
  • 优化关键字节数以缩短下载时间(往返次数)。
  • 优化其余关键资源的加载顺序:您需要尽早下载所有关键资产,以缩短关键路径长度。

https://developers.google.com/web/fundamentals/performance/critical-rendering-path/page-speed-rules-and-recommendations

sl1673495 avatar May 10 '20 12:05 sl1673495

HTTP1 的缺点

在 HTTP/1.0 中,一个服务器在发送完一个 HTTP 响应后,会断开 TCP 链接。但是这样每次请求都会重新建立和断开 TCP 连接。 Connection: keep-alive 的 Header 可以优化这个问题。

但是一个 TCP连接中的多个HTTP请求是不能并行发送的,单个 TCP 连接在同一时刻只能处理一个请求。

所以 HTTP1 时代的性能优化:

  1. 打包资源以减少HTTP请求,比如雪碧图。
  2. 维持和服务器已经建立的 TCP 连接,在同一连接上顺序处理多个请求。
  3. 和服务器建立多个 TCP 连接,对资源的域进行分片。
  4. 内联比较小的资源。

HTTP2 带来的性能优化

https://developers.google.com/web/fundamentals/performance/http2

数据流、消息和帧

新的二进制分帧机制改变了客户端与服务器之间交换数据的方式。 为了说明这个过程,我们需要了解 HTTP/2 的三个概念:

  • 数据流:已建立的连接内的双向字节流,可以承载一条或多条消息。
  • 消息:与逻辑请求或响应消息对应的完整的一系列帧。
  • 帧:HTTP/2 通信的最小单位,每个帧都包含帧头,至少也会标识出当前帧所属的数据流。

这些概念的关系总结如下:

  • 所有通信都在一个 TCP 连接上完成,此连接可以承载任意数量的双向数据流。
  • 每个数据流都有一个唯一的标识符和可选的优先级信息,用于承载双向消息。
  • 每条消息都是一条逻辑 HTTP 消息(例如请求或响应),包含一个或多个帧。
  • 帧是最小的通信单位,承载着特定类型的数据,例如 HTTP 标头、消息负载等等。 来自不同数据流的帧可以交错发送,然后再根据每个帧头的数据流标识符重新组装。

image

http://www.blogjava.net/yongboy/archive/2015/03/19/423611.aspx

sl1673495 avatar May 10 '20 13:05 sl1673495

资源优先级

https://developers.google.com/web/fundamentals/performance/resource-prioritization

image

preload 预加载

<link rel="preload"> 告知浏览器当前导航需要某个资源,应尽快开始提取。 以下为相关使用示例:

preconnect 预连接

<link rel="preconnect"> 告知浏览器您的页面打算与另一个起点建立连接,以及您希望尽快启动该过程。

在速度较慢的网络中建立连接通常非常耗时,尤其是要建立安全连接时,因为这一过程可能涉及 DNS 查询、重定向以及指向处理用户请求的最终服务器的若干往返。 提前处理好上述事宜将使您的应用提供更加流畅的用户体验,且不会为带宽的使用带来负面影响。 建立连接所消耗的时间大部分用于等待而不是交换数据。

注:实际上,还有一种与连接相关的 类型: <link rel="dns-prefetch">。 此类型仅处理 DNS 查询,因此它属于 <link rel="preconnect"> 的小型子集,但因其受浏览器的支持更广泛,可作为不错的回退方案。 使用方法完全一样: <link rel="dns-prefetch" href="https://example.com">

prefetch 预提取

<link rel="prefetch"> 它并不试图使关键操作更快发生,而是利用机会使非关键操作更早发生。当前页面完成加载后,且带宽可用的情况下,这些资源将在 Chrome 中以 Lowest 优先级被提取。

例如检索结果列表中首个产品的详情页面或检索分页内容的下一页。

<link rel="prefetch" href="page-2.html">

sl1673495 avatar May 11 '20 04:05 sl1673495