面试官:从输入URL到页面渲染,有哪些地方可以优化

323 阅读9分钟

前言

春招在继续,面试不停息!最近也是被问到了标题上这个问题,好家伙,一个问题问到了URL到页面渲染的过程和性能优化,如果不熟悉这个过程的话,回答起来确实挺费劲,这篇文章就将带大家来捋一捋,争取回答的时候不卡壳 ~

输入 URL 到页面渲染过程

1.URL 解析

首先浏览器会判断你输入的是一个合法的URL 还是一个待搜索的关键词,如果是关键词,则会将关键词发送给默认的搜索引擎,然后返回页面;如果是URL,则会对URL的结构进行解析。

image.png

2.DNS 解析

当浏览器解析出域名,它会向DNS服务器发送请求,获取相应域名对应的IP地址。

  • 首先搜索浏览器的 DNS 缓存,缓存中维护一张域名与 IP 地址的对应表
  • 若没有命中,则继续搜索操作系统的 DNS 缓存
  • 若仍然没有命中,则操作系统将域名发送至本地域名服务器,本地域名服务器采用递归查询自己的 DNS 缓存,查找成功则返回结果
  • 若本地域名服务器的 DNS 缓存没有命中,则本地域名服务器向上级域名服务器进行迭代查询
    • 首先本地域名服务器向根域名服务器发起请求,根域名服务器返回顶级域名服务器的地址给本地服务器
    • 本地域名服务器拿到这个顶级域名服务器的地址后,就向其发起请求,获取权限域名服务器的地址
    • 本地域名服务器根据权限域名服务器的地址向其发起请求,最终得到该域名对应的 IP 地址
  • 本地域名服务器将得到的 IP 地址返回给操作系统,同时自己将 IP 地址缓存起来
  • 操作系统将 IP 地址返回给浏览器,同时自己也将 IP 地址缓存起来
  • 至此,浏览器就得到了域名对应的 IP 地址,并将 IP 地址缓存起来

image.png

3.TCP 三次握手建立连接

浏览器向服务器发起 TCP 连接请求,与服务器建立连接。

  1. 客户端向服务器发送连接请求:客户端首先向服务器发送一个 SYN 报文段,指定客户端的初始序列号,并设置 SYN 标志位为 1,表示请求建立连接。
  2. 服务器响应确认连接请求:服务器接收到客户端的 SYN 报文段后,会向客户端发送一个 ACK 报文段作为确认,同时也发送一个 SYN 报文段。服务器在 SYN 报文段中指定服务器的初始序列号,并设置 SYN 和 ACK 标志位为 1,表示确认客户端的连接请求,并请求建立连接。
  3. 客户端确认连接:客户端收到服务器的 SYN 报文段后,会向服务器发送一个 ACK 报文段作为确认。客户端设置 ACK 标志位为 1,表示确认服务器的连接请求,建立连接。

image.png

4.发起 HTTP 请求

当建立TCP连接之后,浏览器就可以发送 HTTP 请求到目标服务器,请求的内容包括:

  • 请求行: 请求方法、请求的 URL、HTTP 协议的版本
  • 请求头部: 包含了关于客户端、请求、所需资源等的信息(Host、User-Agent 等等)
  • 请求体(仅在向服务器发送数据时才有):包含了要发送给服务器的数据,如表单数据、JSON 数据等。

5.服务器响应

服务器接收到请求后,返回相应的资源数据,响应的内容包括:

  • 状态行: 包含了 HTTP 协议的版本、状态码和状态消息。
  • 响应头: 包含了关于响应、服务器、所返回资源等的信息(Content-Type、Content-Length 等等)。
  • 响应体: 包含服务器返回给客户端的实际数据,如HTML 页面、图片等。

6.浏览器解析渲染页面

1.构建 DOM 树

  1. 词法分析
    • 浏览器接收到 HTML 字符串后,会将其分解成一系列的标记(tokens)。
    • 标记包括开始标签、结束标签、属性、文本内容等。
  2. 解析标记
    • 浏览器根据词法分析得到的标记,开始解析这些标记并构建 DOM 节点。
    • 当解析到开始标签时,浏览器创建对应的元素节点,并将其加入 DOM 树中。
    • 当解析到属性时,浏览器将属性添加到对应的元素节点上。
    • 当解析到文本内容时,浏览器创建文本节点,并将其加入到 DOM 树中。
  3. 构建 DOM 树
    • 在解析过程中,浏览器会根据标记的嵌套关系构建出完整的 DOM 树结构。
    • 根据 HTML 文档的层次结构,浏览器将创建的元素节点和文本节点按照其在文档中的位置进行组织,形成一棵树状结构。

image.png

2.构建 CSSOM 树

  1. 词法分析
    • 浏览器接收到 CSS 字符串后,会将其分解成一系列的标记(tokens)。
    • 标记包括选择器、属性、属性值等。
  2. 解析样式表
    • 浏览器根据词法分析得到的标记,开始解析这些标记并构建 CSSOM 节点。
    • 当解析到选择器时,浏览器创建对应的规则节点,并将其加入 CSSOM 树中。
    • 当解析到属性和属性值时,浏览器将其添加到对应的规则节点上。
  3. 计算优先级
    • 在解析过程中,浏览器会确定样式的优先级。
  4. 处理样式继承
    • 浏览器会处理样式的继承关系,将父元素的样式属性应用到子元素上。
  5. 解析样式表引用
    • 如果样式表中包含了 @import 规则,浏览器会解析引入的外部样式表,并将其内容合并到当前的 CSSOM 树中。
  6. 合并样式表(Merging Stylesheets)
    • 如果页面中包含多个样式表,浏览器会将这些样式表合并成一个统一的 CSSOM 树。

image.png

3.构建渲染树

浏览器将 DOM 树和 CSSOM 树合并成渲染树(Render Tree)。

  1. 从 DOM 树和 CSSOM 树中选择可见元素
    • 首先,浏览器需要从 DOM 树和 CSSOM 树中选择出在页面中可见的元素。
    • 不可见的元素,如 <head>script 标签内的内容等,不会包含在渲染树中。
  2. 匹配样式规则
    • 对于渲染树中的每个可见元素,浏览器会根据其标签和属性等信息,匹配适用的 CSS 样式规则。
  3. 计算最终样式
    • 当一个元素匹配到多个 CSS 样式规则时,浏览器会根据优先级和层叠规则计算出最终的样式值。
  4. 生成渲染树
    • 当所有可见元素都被匹配样式并加入渲染树后,渲染树的构建过程就完成了。

image.png

4.回流

有了渲染树,再接着就要进入回流(Reflow),也称为重新布局(Layout),浏览器根据渲染树中每个节点的布局信息,计算各个节点在页面中的位置和大小。当页面中的元素尺寸、位置或可见性发生变化时,浏览器需要重新计算并更新页面的布局信息。

5.重绘

回流一定伴随着重绘(Repaint),重绘是指浏览器根据元素的样式信息重新绘制页面的过程,而不涉及布局的改变。浏览器根据布局信息,将页面内容绘制到屏幕上。当元素的样式属性(如颜色、背景色、文本等)发生变化时,会触发重绘操作。

性能优化

1.DNS 解析优化

  • 使用快速的 DNS 服务器,可以借助 CDN ,减少域名解析时间。
  • 减少不必要的域名解析,合并资源到尽可能少的域名。

2.建立 TCP 连接优化

  • 使用 HTTP/2 以上版本协议,充分利用多路复用功能,减少连接建立时间。
  • 减少不必要的 TCP 连接,通过合并或内联资源来减少连接建立次数。

3.发起 HTTP 请求优化

  • 减少 HTTP 请求次数,通过合并或内联资源来减少请求次数(比如图片资源可以考虑懒加载图片或使用精灵图)。
  • 使用资源预加载和预解析来预先加载页面所需资源。<link rel="preload"><link rel="prefetch">

4.服务器响应优化

  • 使用 CDN 加速资源传输,提高服务器响应速度。
  • 启用服务器端缓存,缓存动态生成的内容或数据库查询结果,减少服务器压力和响应时间。

5.资源下载优化

  • 减小资源文件大小,如优化图片(使用 WebP 格式)、压缩 JavaScript 和 CSS。
  • 使用浏览器缓存(Cache-Control、Expires),减少对服务器的请求,尤其是静态资源。
  • 使用异步加载 <script async><script defer>

6.HTML 解析优化

  • 编写语义化的 HTML,避免过多嵌套和冗余标签。
  • 减小 HTML 文件大小,去除不必要的空格和注释。

7.CSS 解析优化

  • 减少 CSS 文件大小,删除不必要的样式和选择器。
  • 避免使用昂贵的 CSS 选择器(尽量给每一个标签给定类名,不要嵌套),优化样式表性能。

8.构建渲染树优化

  • 减少不必要的 DOM 操作,优化 JS 执行性能。
  • 避免使用 JS 动态修改样式,尽量使用 CSS 实现动画效果。

9.回流优化

  • 使用新布局(Flexbox 或 Grid 布局),减少复杂的布局计算。
  • 避免频繁修改样式属性,尽量使用批量修改或者使用类名切换的方式。

10.重绘优化

  • 使用 transform 和 opacity 属性来触发硬件加速,减少页面重绘次数。
  • 避免在页面加载过程中阻塞渲染,尽快将页面内容呈现给用户。
  • 如果需要操作DOM,先让DOM脱离文档流,再修改,再带回文档流(或者使用DocumentFragment),减少回流重绘。

参考

最后

码字不易,感谢三连!

已将学习代码上传至 github,欢迎大家学习指正!

技术小白记录学习过程,有错误或不解的地方还请评论区留言,如果这篇文章对你有所帮助请 “点赞 收藏+关注” ,感谢支持!!