JavaScript篇:从输入网址到页面展现,浏览器背后都干了啥?

80 阅读5分钟

🎓 作者简介前端领域优质创作者

🚪 资源导航: 传送门=>

🎬 个人主页:  江城开朗的豌豆

🌐 个人网站:    江城开朗的豌豆 🌍

📧 个人邮箱: YANG_TAO_WEB@163.com 📩

💬 个人微信:     y_t_t_t_ 📱

📌  座  右 铭: 生活就像心电图,一帆风顺就证明你挂了 💔

👥 QQ群:  906392632 (前端技术交流群) 💬

大家好,我是[小杨],今天我们来聊聊一个看似简单却暗藏玄机的问题:当我在浏览器地址栏输入一个网址并按下回车后,到底发生了什么? 这个过程看似瞬间完成,实际上浏览器在背后默默执行了十几个关键步骤。作为前端开发者,理解这个过程对性能优化和问题排查都很有帮助。

1. 整体流程概览

先来看下完整流程的简化版:

  1. 输入URL并回车
  2. DNS解析:把域名变成IP地址
  3. 建立TCP连接:和服务器三次握手
  4. 发送HTTP请求
  5. 服务器处理请求并返回响应
  6. 浏览器解析渲染页面
  7. 连接关闭(如果是HTTP/1.1可能会保持连接)

下面我们拆解每个环节,用通俗易懂的方式讲清楚。

2. 详细步骤解析

2.1 第一步:URL解析

当我在地址栏输入 https://www.example.com 并回车时,浏览器首先会:

  • 检查输入的内容是URL还是搜索关键词
  • 如果是URL,判断协议(http/https)是否完整,不完整会自动补全
  • 对特殊字符进行编码处理(比如空格变成%20

2.2 第二步:DNS域名解析

浏览器不能直接通过域名找到服务器,需要先转换成IP地址:

  1. 浏览器缓存:看之前是否访问过这个网站
  2. 系统缓存(如Mac的/etc/hosts文件)
  3. 路由器缓存
  4. ISP的DNS服务器(比如电信/联通的DNS)
  5. 如果还是找不到,会进行递归查询直到根域名服务器
// 类似这样的DNS查询过程(伪代码)
function findIP(domain) {
  if (浏览器缓存有domain) return 缓存IP;
  if (系统hosts文件有记录) return hosts中的IP;
  向本地DNS服务器查询();
  if (本地DNS服务器有记录) return 结果;
  向更高级DNS服务器递归查询();
  return 最终IP;
}

2.3 第三步:建立TCP连接

拿到IP后,浏览器要通过三次握手和服务器建立TCP连接:

  1. 浏览器 → 服务器:发送SYN=1(同步)报文
  2. 服务器 → 浏览器:回复SYN=1, ACK=1(确认)
  3. 浏览器 → 服务器:发送ACK=1
# 三次握手示意图
浏览器      服务器
  |----SYN---->| 
  |<--SYN+ACK--|
  |----ACK---->|

如果是HTTPS,还会额外进行TLS握手(交换密钥、验证证书等)。

2.4 第四步:发送HTTP请求

TCP连接建立后,浏览器发送真正的HTTP请求:

GET / HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0
Accept: text/html
Cookie: name=我

这个请求头包含了:

  • 请求方法(GET/POST等)
  • 需要的资源路径(/表示首页)
  • 浏览器信息(User-Agent)
  • 支持的压缩格式(Accept-Encoding)
  • 携带的Cookie(如果有)

2.5 第五步:服务器处理请求

服务器收到请求后:

  1. Web服务器(如Nginx)接收请求
  2. 可能转发给应用服务器(如Node.js/Java)
  3. 查询数据库获取数据
  4. 生成HTML响应(或返回JSON等数据)
// 伪代码示例:Node.js处理请求
app.get('/', (req, res) => {
  const user = db.query('SELECT * FROM users WHERE name = "我"');
  res.render('index', { user });
});

2.6 第六步:浏览器解析渲染

服务器返回HTML后,浏览器开始关键渲染路径:

  1. 解析HTML → 构建DOM树
  2. 解析CSS → 构建CSSOM树
  3. 合并成渲染树
  4. 布局计算(Layout)
  5. 绘制(Paint)
graph TD
    A[HTML] --> B(DOM树)
    C[CSS] --> D(CSSOM树)
    B --> E(渲染树)
    D --> E
    E --> F[布局]
    F --> G[绘制]

如果遇到<script>标签会暂停HTML解析,先执行JS(除非加了async/defer)。

2.7 第七步:加载其他资源

页面中引用的图片、CSS、JS等会触发额外请求:

<!-- 这些标签都会产生新的HTTP请求 -->
<link rel="stylesheet" href="style.css">
<script src="app.js"></script>
<img src="me.jpg" alt="我">

浏览器会并行下载这些资源(HTTP/1.1有并发限制,HTTP/2可以多路复用)。

3. 性能优化关键点

理解了流程后,我们可以针对性优化:

  1. 减少DNS查询:使用DNS预加载<link rel="dns-prefetch">
  2. 减少TCP连接:使用HTTP/2、合并域名
  3. 压缩资源:Gzip、Brotli压缩
  4. 缓存策略:设置Cache-Control
  5. 减少重绘回流:避免频繁操作DOM

4. 实际案例演示

假设我的个人博客(https://myblog.com)加载很慢,通过Chrome DevTools分析发现:

  • 首次加载耗时2s(主要卡在DNS查询和TCP连接)
  • 图片未压缩,多消耗800KB流量
  • JS文件阻塞渲染

优化方案:

  1. 配置DNS预加载
  2. 启用CDN加速
  3. 压缩图片为WebP格式
  4. 给JS添加defer属性

优化后加载时间降到800ms!

5. 总结

从输入URL到页面展示,主要经历:

  1. URL解析 → 2. DNS查询 → 3. TCP握手
  2. HTTP请求 → 5. 服务器处理 → 6. 渲染解析

理解这个过程后,无论是调试页面加载问题,还是做性能优化,都能更加得心应手。希望这篇文章对你有帮助,如果有疑问欢迎在评论区讨论~