90% 的人只知道 DNS 解析,却忽略了浏览器进程的“暗中操作”

3 阅读7分钟

前言

“在浏览器地址栏输入 URL 到页面显示,中间发生了什么?”

这道题堪称前端面试界的**“镇山之宝”**。很多同学背了八股文,但一被追问细节就卡壳:DNS 到底怎么查的?浏览器进程和渲染进程啥关系?TCP 握手在哪一步?

今天,我们不枯燥地罗列概念,而是把浏览器想象成一家**“超级餐厅”**。你(用户)是顾客,浏览器是餐厅管理系统。让我们跟着这道“网页大餐”,从点单到上桌,彻底理清浏览器的多线程/多进程架构!

📝 本文基于最新浏览器架构(多进程模型),建议收藏 + 点赞,面试前看一遍!


🏢 角色介绍:浏览器的“后厨团队”

现代浏览器(如 Chrome)是一个多进程架构,为了不让一个标签页崩溃导致整个浏览器挂掉,它把工作分给了不同的“员工”:

  1. 浏览器进程 (Browser Process) 🧑‍💼:餐厅经理。负责界面显示、标签页管理、协调其他进程。
  2. 网络进程 (Network Process) 🛒:采购员。负责网络请求、DNS 解析、资源下载。
  3. 渲染进程 (Renderer Process) 👨‍🍳:厨师。最核心的角色,负责解析 HTML/CSS、执行 JS、绘制页面。
  4. 插件进程/GPU 进程:辅助人员(本文暂不展开)。

第一阶段:点单与备料(浏览器进程 & 网络进程)

当你按下回车键的那一刻,餐厅经理(浏览器进程) 首先介入。

1. 预处理与 URL 补全

经理先看你点的什么菜(URL)。

  • 检查缓存:经理先翻翻冰箱(本地缓存),如果有现成的,直接端给你,跳过后续步骤。
  • URL 补全:如果你只输入了 baidu,经理会根据默认搜索引擎帮你补全成 https://www.baidu.com
  • 协议补全:自动加上 http://https://

2. DNS 解析:寻找“供应商”地址

经理把任务交给 采购员(网络进程)。采购员拿着域名(如 www.example.com),需要找到服务器的 IP 地址(门牌号)。

💡 为什么需要 DNS? 计算机只认 IP 地址(如 142.250.1.1),但人记不住。DNS 就是互联网的电话簿,把域名映射到 IP。

DNS 查找的“层层问路”:

  1. 本地 Hosts 文件(优先级最高 🚩):
    • 这是你电脑本地的“黑名单/白名单”。
    • 路径:C:\Windows\System32\drivers\etc\hosts
    • 场景:本地开发时,你想用 dev.myapp.com 访问本地 127.0.0.1,就可以在这里配置。
  2. 本地 DNS 缓存:浏览器和操作系统会缓存查过的 IP。
    • Chrome 查看命令:chrome://net-internals/#dns
  3. 递归/迭代查询(如果本地没有):
    • 本地 DNS 服务器(运营商提供) -> 没有?
    • 根域名服务器 (.) -> 去问 .com 的
    • 顶级域名服务器 (.com) -> 去问 example.com 的
    • 权威域名服务器 -> 拿到 IP!

🌐 深入一点:一个域名对应多个 IP? 是的!大型网站(如抖音、淘宝)背后是服务器集群。 DNS 返回的 IP 通常是 Nginx 反向代理服务器 的 IP。它像“媒婆”一样,根据负载均衡策略(轮询、地域最近原则),把你引导到最快的机房服务器。

3. 建立连接:TCP 三次握手 & TLS 加密

拿到 IP 后,采购员要去找服务器“谈生意”了。

  • TCP 三次握手(确认双方能收发数据):
    1. 客户端:我要连你 (SYN)
    2. 服务器:好的,我也要连你 (SYN + ACK)
    3. 客户端:好的,连接建立 (ACK)
  • TLS 握手(如果是 HTTPS):协商加密密钥,确保数据传输安全。

4. 发送 HTTP 请求 & 接收响应

连接建立,采购员正式下单:

  • 请求:发送请求行 (GET /index.html HTTP/1.1) 和请求头 (Cookie, User-Agent 等)。
  • 响应:服务器返回响应行 (200 OK) 和响应头。

⚠️ 关键决策点:响应头预处理 在接收正文前,浏览器会根据 Header 做决策:

  • 301/302 重定向:看到 Location 头,立刻重新发起请求(比如 http 跳 https)。
  • 304 未修改:直接用本地缓存,不下载正文。
  • Content-Disposition:如果是 attachment,触发下载,不渲染。
  • Content-Type:决定把数据交给谁处理(HTML 给渲染进程,JSON 给 JS 引擎,图片给解码器)。

第二阶段:提交导航(浏览器进程)

采购员买回了食材(HTML 数据),现在要交给厨师了。这一步叫 提交导航 (Commit Navigation)

  1. 数据校验:浏览器进程检查 Content-Type,确认这是 HTML 而不是一个下载文件。
  2. 更新状态
    • 更新地址栏 URL。
    • 更新会话历史(前进/后退按钮状态)。
    • 触发 beforeunload 事件(如果有旧页面)。
  3. 准备渲染进程
    • 如果是跨域跳转,通常创建新的渲染进程。
    • 如果是同域,可能复用旧的渲染进程(性能优化)。
  4. 建立通道:浏览器进程与渲染进程通过 IPC (进程间通信) 建立连接,准备传输 HTML 数据。

🍽️ 餐厅类比 经理确认买回来的是菜(HTML),不是杂物。更新订单板(地址栏),安排具体的厨师(渲染进程)接手,把食材通过传菜口(IPC)交给厨师。


第三阶段:烹饪大餐(渲染进程)

这是最复杂、最耗时、也是前端优化最核心的阶段。厨师(渲染进程) 开始干活了!

1. 解析 (Parsing)

  • HTML 解析:生成 DOM 树 (Document Object Model)。
  • CSS 解析:生成 CSSOM 树 (CSS Object Model)。
  • JS 执行:遇到 <script> 标签,默认会阻塞 HTML 解析(除非加了 asyncdefer)。
    • 面试题考点:为什么 JS 会阻塞渲染?因为 JS 可能修改 DOM 结构。

2. 构建渲染树 (Render Tree)

将 DOM 和 CSSOM 合并。

  • 剔除隐藏节点display: none 的元素不会进入渲染树(但 visibility: hidden 会,因为它占位)。

3. 布局 (Layout / Reflow)

计算每个节点在屏幕上的确切位置和大小。

  • 比如:这个 div 宽 100px,离左边 20px。
  • 性能警告:频繁操作 DOM 会导致重排 (Reflow),非常消耗性能!

4. 分层 (Layer)

为了优化性能,浏览器会把页面分成不同的层。

  • 比如:视频层、滚动层、Canvas 层。
  • 可以通过 will-changetransform 触发分层(开启 GPU 加速)。

5. 绘制 (Paint)

在每个层上绘制文字、颜色、边框、阴影等,生成位图。

6. 光栅化 (Raster) & 合成 (Composite)

  • 光栅化:将位图转换为 GPU 能识别的网格(Tile),通常生成位图缓存。
  • 合成:GPU 将各个层按照顺序合成,最终显示在屏幕上。

🍽️ 餐厅类比 厨师开始做菜:

  1. 洗菜切菜(解析 HTML/CSS)。
  2. 按食谱搭配(构建渲染树)。
  3. 决定摆盘位置(布局 Layout)。
  4. 把菜分到不同的盘子里(分层 Layer,避免串味/提高效率)。
  5. 炒菜装盘(绘制 Paint & 光栅化 Raster)。
  6. 端给顾客(合成 Composite)。

📝 面试总结 & 性能优化小贴士

如果面试官问你:“在这个过程中,哪里可以做性能优化?” 你可以这样回答:

  1. DNS 阶段:使用 DNS Prefetch 提前解析域名。
  2. 网络阶段
    • 使用 HTTP/2 或 HTTP/3 减少连接开销。
    • 利用强缓存 (Cache-Control) 和协商缓存 (ETag)。
    • 资源压缩 (Gzip/Brotli)。
  3. 渲染阶段
    • 关键渲染路径优化:CSS 放头部,JS 放底部或使用 defer/async
    • 减少重排重绘:使用 transform 代替 top/left,批量修改 DOM。
    • 图片优化:使用 WebP,懒加载 (loading="lazy")。
    • 分层优化:对动画元素开启 GPU 加速。

🎯 结语

从输入 URL 到页面显示,不仅仅是一个网络请求,而是一场浏览器多进程协作的交响乐

  • 浏览器进程 是大脑,负责调度。
  • 网络进程 是手脚,负责获取资源。
  • 渲染进程 是心脏,负责呈现内容。

理解了这个流程,你不仅能从容应对面试,更能明白为什么你的代码会卡顿,从而写出性能更优的前端应用。

觉得文章对你有帮助?欢迎点赞 👍、收藏 ⭐、关注 📢,下期我们深入聊聊“浏览器缓存策略”!


(本文参考了 Chrome 架构设计及相关网络协议标准,内容如有更新请以最新文档为准)