Published on

在浏览器中输入URL并按下回车后会发生什么

Authors
  • Name
    Twitter

引言

作为Web开发者,理解从用户输入URL到页面完全加载的整个过程是至关重要的。

详细流程

1. 输入URL

一切始于用户在浏览器地址栏输入URL(如 https://www.example.com)并按下回车键。

2. URL解析

浏览器首先解析输入的URL,识别出以下组成部分:

  • 协议(https)
  • 域名(www.example.com)
  • 路径
  • 查询参数(如果有)
  • 锚点(如果有)

3. DNS查询

为了与服务器建立连接,浏览器需要知道服务器的IP地址。这就需要进行DNS(域名系统)查询:

  1. 检查浏览器DNS缓存
  2. 检查操作系统DNS缓存
  3. 查询本地hosts文件
  4. 如果以上都未命中,则向配置的DNS服务器发起递归查询

4. TCP连接建立(三次握手)

得到IP地址后,浏览器就会尝试与服务器建立TCP连接。这个过程通常称为"三次握手":

  1. 客户端发送SYN包
  2. 服务器响应SYN-ACK包
  3. 客户端发送ACK包

5. SSL/TLS握手

对于HTTPS连接,在TCP连接建立之后还需要进行SSL/TLS握手,以建立安全通信通道:

  1. 客户端发送支持的加密算法列表和随机数
  2. 服务器选择加密算法,发送证书和自己的随机数
  3. 客户端验证证书,生成预主密钥,用服务器公钥加密后发送
  4. 双方根据共享的信息生成会话密钥

6. 发送HTTP请求

安全连接建立后,浏览器发送HTTP GET请求,包括:

  • 请求行(HTTP方法、路径、协议版本)
  • 请求头(User-Agent、Accept、Cookie等)
  • 请求体(对GET请求通常为空)

7. 服务器处理请求并返回HTTP响应

服务器接收到请求后:

  1. 解析请求
  2. 执行相应的处理(可能涉及数据库查询、业务逻辑等)
  3. 生成HTTP响应
  4. 通过安全连接发送响应给客户端

8. TCP连接终止(四次挥手)

在HTTP响应发送完毕后,通常会发生TCP连接的终止过程,也称为"四次挥手":

  1. 客户端发送FIN包,表示客户端没有数据要发送了
  2. 服务器回送ACK包,确认收到客户端的FIN
  3. 服务器发送FIN包,表示服务器也没有数据要发送了
  4. 客户端回送ACK包,确认收到服务器的FIN

这个过程确保了双方都完成了数据传输,可以安全地关闭连接。值得注意的是,在某些情况下(如使用HTTP keep-alive),TCP连接可能不会立即关闭,而是保持打开状态以供后续请求使用。

9. 浏览器解析HTML

浏览器开始解析接收到的HTML文档。这是一个增量过程,允许浏览器逐步显示页面内容。

10. 构建DOM树

HTML解析器将HTML文档转换成DOM(文档对象模型)树,表示文档的结构和内容。

11. 构建CSSOM树

同时,浏览器解析CSS(内联、内部和外部),构建CSSOM(CSS对象模型)树,表示元素的样式信息。

12. 合并DOM和CSSOM,生成渲染树

浏览器将DOM树和CSSOM树合并,创建渲染树。渲染树只包含需要显示的节点及其样式信息。

13. 重排(Reflow)

计算渲染树中每个节点的精确位置和大小。这个过程也称为"回流"(Reflow)。

重排是布局或几何属性需要改变时发生的过程。以下情况会触发重排:

  1. 添加或删除可见的DOM元素
  2. 元素位置改变
  3. 元素尺寸改变(包括外边距、内边距、边框厚度、宽度、高度等)
  4. 内容改变,如文本改变或图片被另一个不同尺寸的图片替代
  5. 页面渲染初始化
  6. 浏览器窗口尺寸改变

重排是一个昂贵的操作,因为它涉及到重新计算元素的几何属性。

14. 重绘(Repaint)

遍历渲染树,调用UI后端层绘制每个节点,将页面元素转换为实际的像素。

重绘发生在元素的外观发生改变,但布局没有改变时。以下情况会触发重绘:

  1. 改变元素的可见性(visibility)
  2. 改变元素的轮廓(outline)
  3. 改变背景(背景图片、颜色等)
  4. 改变元素的透明度

重绘的代价相对于重排要小,因为它不需要重新计算元素的几何属性。

15. 合成(Compositing)

将不同的绘制层合成到一起,处理重叠元素,确保它们以正确的顺序显示。

重排和重绘的优化

理解重排和重绘的概念对于前端性能优化至关重要。以下是一些减少重排和重绘的策略:

  1. 批量修改DOM:使用文档片段(DocumentFragment)或者将元素设为不可见后进行多次修改,最后再显示。

  2. 避免频繁操作样式:合并多次样式修改,或者使用类名来一次性应用多个样式。

  3. 使用绝对定位使元素脱离文档流:这样修改它们不会影响其他元素。

  4. 优化动画:使用 requestAnimationFrame 来控制动画,避免使用 setTimeout 或 setInterval。

  5. 使用 CSS3 硬件加速:利用 transform、opacityfilters 等属性,这些修改可以通过合成线程进行处理,不会触发重排或重绘。