再来看看「从输入 URL 到看到页面」的整个流程

大家好,我是有一点想法的thinkmars,目前在准备面试与工作,借着间隙时间学习复习,写一点基础文章,欢迎想找工作的人与我一起学习,一起讨饭吃~

前言

理解页面加载流程对于性能优化至关重要,前端性能优化无外乎就是优化这个流程。相对底层的协议来说,前端优化的空间比较小,难度较大,而后端服务通信可以选用一些更高效的协议或者自定义协议。前端优化通常集中在建立连接后的阶段,比如缩短传输距离、减少传输次数、减小资源传输体积、降低浏览器渲染压力、使用资源缓存等等。


整个流程大致分为以下步骤:

1. 输入 URL 并解析

  • 用户行为 :在浏览器地址栏输入 https://www.example.com 并按下回车。
  • 浏览器解析 URL
    • 检查 URL 的协议(https)、域名(www.example.com)、端口(默认443)、路径(/)等。
    • 如果输入的不是完整的 URL,浏览器会尝试补全(比如自动添加http://或搜索关键词)。

2. DNS 域名解析

  • 目的 :将域名(如www.example.com)转换成服务器的 IP 地址(如192.0.2.1)。
  • 具体步骤
    1. 浏览器缓存:检查浏览器是否缓存过该域名的 IP。
    2. 系统缓存:查询本地 hosts 文件或操作系统缓存。
    3. 路由器缓存:检查路由器 DNS 缓存。
    4. ISP DNS 服务器:向互联网服务提供商(如电信、联通)的 DNS 服务器发起请求。
    5. 递归查询 :如果 ISP 的 DNS 没有缓存,会从根域名服务器(.)开始逐级查询:
      • 根域名服务器 → .com顶级域名服务器 → example.com权威域名服务器。
    6. 返回 IP :最终获得www.example.com对应的 IP 地址。
graph TD A[浏览器缓存] --> B[系统缓存] B --> C[路由器缓存] C --> D[ISP DNS服务器] D --> E[根域名服务器] E --> F[顶级域名服务器] F --> G[权威域名服务器] G --> H[返回IP地址]

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

  • 目的:浏览器和服务器通过 TCP 协议建立可靠连接。
  • 三次握手过程
    1. 浏览器 → 服务器 :发送SYN=1, Seq=x(同步请求)。
    2. 服务器 → 浏览器 :回复SYN=1, ACK=x+1, Seq=y(确认并同步)。
    3. 浏览器 → 服务器 :发送ACK=y+1(最终确认)。
  • 结果:连接建立,可以传输数据。
graph LR A[浏览器] -- SYN=1,Seq=x --> B[服务器] B -- SYN=1,ACK=x+1,Seq=y --> A A -- ACK=y+1 --> B

4. 发送 HTTP 请求

  • 浏览器构造 HTTP 请求 ,例如:

    http 复制代码
    GET / HTTP/1.1
    Host: www.example.com
    User-Agent: Chrome/...
    Accept: text/html, */*
  • 如果是 HTTPS

    • 先进行 TLS 握手(交换密钥、验证证书)。
    • 加密后续通信内容。

5. 服务器处理请求

  • Web 服务器(如 Nginx/Apache)
    • 解析请求路径,可能转发给后端应用(如 PHP、Node.js)。
  • 后端应用
    • 处理业务逻辑(如查询数据库)。
    • 生成 HTML 响应(或 JSON 数据)。

6. 服务器返回 HTTP 响应

  • 响应示例

    http 复制代码
    HTTP/1.1 200 OK
    Content-Type: text/html
    Content-Length: 1234
    
    <!DOCTYPE html>
    <html>...</html>
  • 状态码200表示成功,404表示页面不存在等。


7. 浏览器解析和渲染页面

  1. 解析 HTML:构建 DOM 树(文档对象模型)。
  2. 解析 CSS:构建 CSSOM 树(CSS 样式规则)。
  3. 合并为渲染树 :结合 DOM 和 CSSOM,排除不可见元素(如<head>)。
  4. 布局(Layout):计算每个元素的位置和大小。
  5. 绘制(Paint):将像素点绘制到屏幕上。
  6. 执行 JavaScript
    • 如果遇到<script>标签,会暂停 HTML 解析,先执行 JS(除非标记为asyncdefer)。
graph TD A[解析HTML] --> B[构建DOM树] B --> C[解析CSS] C --> D[构建CSSOM树] D --> E[合并渲染树] E --> F[布局计算] F --> G[绘制页面] G --> H[执行JavaScript] H -->|遇到