从输入 URL 到页面渲染完整流程详解
目录
- 一、从输入 URL 到发起网络请求前
- 二、DNS 解析:把域名解析为 IP
- 三、建立连接(TCP 三次握手 + TLS 握手)
- 四、HTTP 请求与首个响应(HTML 文档)
- 五、浏览器渲染流水线(HTML → 最初可见页面)
- 六、JS 执行、异步网络请求与后续渲染更新
- 七、缓存、优化与后续访问
- 八、完整流程图
- 九、面试高频考点总结
- 十、性能优化建议
一、从输入 URL 到发起网络请求前
1.1 地址栏输入与协议/目标识别
当你在浏览器中输入:
https://www.baidu.com/
浏览器会进行以下判断:
- 判断输入类型
- 如果输入符合 URL 格式(如
https://www.baidu.com/)→ 当作 URL 处理 - 如果输入是普通文本 → 可能走默认搜索引擎
- 如果输入符合 URL 格式(如
- 解析 URL 结构
- 协议:
https - 主机名:
www.baidu.com - 端口:默认 443(HTTPS)
- 路径:
/(根路径)
- 协议:
1.2 浏览器进程与渲染进程协调
现代浏览器一般采用多进程架构(以 Chrome 为例):
- 浏览器进程:负责 UI、网络、进程管理等
- 渲染进程:负责每个 Tab 的页面渲染、JS 执行
流程:
- 浏览器进程接收到导航请求(你敲回车)
- 为
https://www.baidu.com/选择或创建一个新的 渲染进程 - 在真正开始加载前,会先进行 安全策略检查(比如 HSTS、本地策略等)
二、DNS 解析:把域名解析为 IP
2.1 查找本地缓存与系统缓存
目标是把 www.baidu.com 解析为 IP 地址(例如 220.x.x.x,具体由 DNS 解析结果决定):
浏览器会依次查询:
- 浏览器自身 DNS 缓存
- 如果近期访问过,可能已有缓存条目
- 本机操作系统 DNS 缓存
- hosts 文件
- 如 Windows 的
C:\Windows\System32\drivers\etc\hosts,如果有显式映射,则直接使用
- 如 Windows 的
2.2 递归 DNS 查询(若本地未命中)
如果上述均未命中,操作系统会向配置的 本地域名服务器(通常为路由器或 ISP DNS)发起请求,具体流程:
- 本地 DNS 服务器如果没有缓存,则进行递归查询:
- 访问 根域名服务器(.) → 找到
.com顶级域名服务器 - 向 .com TLD 服务器 查询
baidu.com→ 获得权威 DNS 服务器地址 - 向 baidu.com 的权威 DNS 查询
www.baidu.com→ 得到最终 IP
- 访问 根域名服务器(.) → 找到
- 结果在各级 DNS 缓存中存储一段时间(TTL)
浏览器最终拿到 www.baidu.com 对应的 一个或多个 IP 地址。
三、建立连接(TCP 三次握手 + TLS 握手)
3.1 选择 IP 与端口
浏览器:
- 可能有多个 IP(多机房/多 CDN 节点),根据策略选择一个
- 对于
https,默认端口为 443
3.2 TCP 三次握手
在客户端和服务器之间建立 TCP 连接(可靠的字节流通道):
- SYN:客户端 → 服务器,发送 SYN 包请求建立连接
- SYN-ACK:服务器 → 客户端,确认并同意连接
- ACK:客户端 → 服务器,确认收到,连接建立
此时,TCP 连接已建立,但 HTTPS 还未开始加密通信。
3.3 TLS/SSL 握手(HTTPS)
为实现加密通信和身份验证,进行 TLS 握手:
- ClientHello
- 浏览器发送支持的 TLS 版本、加密套件列表、随机数等
- ServerHello + 证书
- 服务器选择加密套件,返回:
- 服务器证书(包含
baidu.com或*.baidu.com的公钥信息) - 服务器随机数等
- 服务器证书(包含
- 服务器选择加密套件,返回:
- 证书验证(前端本机执行)
- 浏览器在本地:
- 检查证书是否由受信任 CA 签发
- 检查证书域名是否与
www.baidu.com匹配 - 检查证书有效期、是否被吊销等
- 如果验证失败,会弹出安全告警
- 浏览器在本地:
- 生成对称密钥
- 根据协商的算法(如 ECDHE),客户端与服务器共同生成 会话密钥
- 使用服务器公钥和密钥交换算法生成、协商对称密钥
- 完成握手
- 双方使用对称密钥进行后续所有数据加解密
此时,安全加密信道建立完成。
四、HTTP 请求与首个响应(HTML 文档)
4.1 发送首个 HTTP 请求
浏览器通过已建立的 TLS+TCP 连接发送 HTTP 请求:
- 请求行:
GET / HTTP/1.1
- 请求头(示例):
Host: www.baidu.comUser-Agent: ...(浏览器信息)Accept: text/html,application/xhtml+xml,application/xml,...Accept-Language: zh-CN,zh;q=0.9,...Cookie: ...(此前在baidu.com下存储的 cookie)Connection: keep-aliveUpgrade-Insecure-Requests: 1- 等等…
4.2 服务器处理请求(后端)
虽然这是后端行为,但前端需要理解结果:
- 服务器根据请求路径
/、cookie、UA 等:- 做路由与鉴权
- 查询数据库、调用内部服务
- 生成 HTML 或响应一个重定向(例如
302到某个特定路径)
- 如果是重定向,浏览器会 再次发起请求 到新的 URL(重复上述一部分流程,但通常复用同一连接)
4.3 接收首个 HTTP 响应
服务器返回:
- 状态行:如
HTTP/1.1 200 OK - 响应头(关键跟前端相关):
Content-Type: text/html; charset=UTF-8Content-Length: ...Cache-Control,ETag,Last-Modified等缓存策略Set-Cookie(设置或更新 cookie)Content-Encoding: gzip/br(压缩)Strict-Transport-Security(强制 HTTPS)Server,Date等
- 响应体:HTML 文档内容(比如百度首页的 HTML 结构)
浏览器解压编码(如 gzip/br),得到原始 HTML 文本。
五、浏览器渲染流水线(HTML → 最初可见页面)
从这里开始,前端工程师最关心的 渲染流程。
5.1 构建 DOM(解析 HTML)
- 边下载边解析:
- HTML 数据流从网络层到达渲染进程后,HTML 解析器会 一边接收、一边解析
- 解析过程:
- 词法分析(Tokenizer):将字节流解码为字符、再分成标签、文本、注释等 token
- 语法分析(Parser):根据 HTML 规范生成树形结构——DOM(Document Object Model)
- 特殊标签处理:
<script>遇到非defer/async的脚本通常会 阻塞解析,必须先下载并执行,再继续往后解析<link rel="stylesheet">(CSS)通常会 阻塞后续渲染阶段(影响样式计算)
5.2 加载外部资源(CSS/JS/图片等)
当解析到外链资源时:
<link rel="stylesheet" href="...">→ 加入 CSS 下载队列<script src="...">→ 加入 JS 下载队列(同步/异步的行为不同)<img src="...">、<video>、<audio>、<iframe>等 → 各自加入下载队列- 浏览器有资源 并发下载限制(通常每个域名有限制),会进行优先级调度:
- HTML/CSS/同步 JS 优先级更高
- 图片、视频等次之
5.3 构建 CSSOM(解析 CSS)
当 CSS 文件(或 <style> 内嵌 CSS)下载完成后:
- 解析 CSS 文本 → 构建 CSSOM(CSS Object Model)
- 处理:
- 选择器解析(如
.logo,#header,div > p等) - 继承与层叠(Cascade),计算出每个选择器的 优先级(specificity)
- 选择器解析(如
- 最终用于后续样式计算
5.4 构建 Render Tree(渲染树)
有了 DOM 与 CSSOM 后:
- 将二者结合,计算每个 DOM 节点的 最终计算样式(Computed Style)
- 过滤掉 不可见的节点(如
display: none的元素),生成 Render Tree:- Render Tree 的节点与 DOM 不完全一一对应
- 某些 DOM 节点不会生成渲染对象
5.5 布局(Layout / Reflow)
在 Render Tree 上进行布局计算:
- 确定每个渲染对象的:
- 几何信息(位置
x,y,尺寸width/height) - 受
box model、position、flex/grid等影响
- 几何信息(位置
- 会从根节点(如
html)开始,自上而下计算:- 父元素决定子元素的可用空间和布局方式
布局完成后,浏览器已经知道 每个可见元素的精确位置与大小。
5.6 绘制(Painting)与合成(Compositing)
- 绘制列表(Paint)
- 浏览器遍历 Render Tree,生成绘制指令列表(如背景、文本、边框、阴影等)
- 分层(Layering)
- 具有特定属性的元素会被提升为 独立图层(如 3D transform、position: fixed、某些动画元素)
- 栅格化(Rasterization)
- 图层在 GPU 进程中被栅格化成位图纹理(Tiles)
- 合成(Compositing)
- 在 GPU 上将各图层根据层级、透明度等规则合成最终画面
- 首屏渲染
- 首次绘制完成后,用户能看到 "首屏内容"
此时,页面可能还在继续加载资源,但已经 可见可操作。
六、JS 执行、异步网络请求与后续渲染更新
6.1 执行同步 JS
在 HTML 解析阶段:
- 遇到
<script>标签(同步加载,未带async/defer):- 如果
src外链,则先阻塞解析,下载脚本 - 下载完成后在 主线程执行 JS
- 如果
- JS 执行期间可以:
- 读写 DOM(
document.getElementById,innerHTML等) - 读写样式(
element.style或getComputedStyle) - 注册事件监听(
addEventListener) - 发送 Ajax / Fetch 请求
- 读写 DOM(
执行完毕后,HTML 解析器继续往下解析。
6.2 async / defer 脚本与模块脚本
<script async>- JS 文件下载 与 HTML 解析并行
- 一旦下载完成,立即执行(可能在 DOMReady 前后不确定)
<script defer>- JS 文件下载与解析并行
- 在 DOM 解析完成后按顺序执行(在 DOMContentLoaded 前)
type="module"- 默认
defer行为,支持 ES Modules 的导入导出
- 默认
这些策略影响 首屏渲染速度 和 JS 执行时机。
6.3 异步网络请求(XHR / Fetch / WebSocket)
JS 执行中常发起二次请求:
- XMLHttpRequest / Fetch
- 通常用于获取 JSON 数据、模板等
- 请求完成后通过回调 / Promise / async-await 更新 DOM
- WebSocket
- 建立长连接,实现实时通信
- EventSource / SSE
- 服务器推送
每次异步数据返回后,如果 JS 修改 DOM 或样式,都会引发 回流(Reflow)或重绘(Repaint)。
6.4 回流(Reflow)与重绘(Repaint)
- 回流(Layout/Reflow):当更改影响到 布局(如元素尺寸、结构、字体大小等):
- 需要重新计算部分或全部的布局
- 随后进行绘制和合成
- 重绘(Repaint):仅更改 外观 不影响布局(如
color、background):- 只需重新绘制,不必重新布局
- 浏览器会尽量合并这些操作,以减少性能损耗
6.5 事件循环(Event Loop)与页面交互
页面进入稳定阶段后:
- 浏览器主线程执行 事件循环:
- 从任务队列中取出任务(如用户交互事件、定时器回调、网络回调)
- 执行回调 → 更新 DOM → 再次触发渲染流程(布局/绘制等)
- 用户与页面交互(输入搜索词、点击按钮)时:
- 事件被分发到页面 JS 事件监听器
- 业务逻辑处理、再次发起网络请求、更新 DOM,渲染刷新
七、缓存、优化与后续访问
7.1 HTTP 缓存
浏览器会根据响应头进行缓存管理:
- 强缓存:
Cache-Control: max-age=...、Expires等- 在有效期内,直接使用本地缓存,不会访问服务器
- 协商缓存:
- 使用
ETag/If-None-Match,Last-Modified/If-Modified-Since - 如果资源未变更,服务器返回
304 Not Modified,节省带宽
- 使用
这会极大提升下次打开页面的速度。
7.2 连接复用与 HTTP/2 / HTTP/3
现代站点通常使用:
- HTTP/2 或 HTTP/3:
- 多路复用:一个连接上传输多个请求/响应,减少 TCP 连接开销
- 头部压缩、服务器推送(H2)等
- 这些都在网络层提升整体加载性能
7.3 Service Worker 与离线缓存(若站点支持 PWA)
如果网站注册了 Service Worker:
- 首次访问时安装 SW,后续请求会被 SW 拦截
- 可实现:
- 请求缓存策略控制(Cache First、Network First 等)
- 离线访问部分资源
- 后台同步、推送等能力
八、完整流程图
九、面试高频考点总结
9.1 从地址栏到发请求前发生了什么?
答案要点:
- 解析输入:判断是 URL 还是搜索关键字;解析出协议/域名/端口/路径
- 进程准备:浏览器进程选择/创建渲染进程,做基础安全检查
- DNS 解析:依次查浏览器缓存 → 系统缓存 → hosts → 本地 DNS → 根/TLD/权威 DNS,得到 IP
- 建立连接:TCP 三次握手 + TLS 握手(HTTPS),验证证书、协商对称密钥
9.2 HTTP 请求和响应关键点?
答案要点:
- 请求:
GET / HTTP/1.1+ 各类请求头(Host、UA、Cookie、Accept 等) - 响应:状态码(200/301/302/304 等)、
Content-Type、缓存相关头(Cache-Control/ETag/Last-Modified)、Set-Cookie等 - 重定向/缓存:可能 301/302 重定向,304 协商缓存,下次访问可能直接走强缓存
9.3 浏览器渲染主流程?(核心背诵点)
答案要点:
- HTML 解析:字节流 → 字符 → Token → DOM 树,遇到同步
<script>会阻塞解析 - CSS 解析:加载
<link>/<style>,解析为 CSSOM - 构建渲染树:DOM + CSSOM → Render Tree(过滤
display:none等不可见节点) - 布局(Reflow/Layout):计算每个渲染对象的几何信息(位置、尺寸)
- 绘制(Paint):生成绘制指令,分层、栅格化
- 合成(Compositing):GPU 合成各图层,输出到屏幕 → 首屏渲染完成
9.4 JS 在里面扮演什么角色?
答案要点:
- 同步脚本:阻塞 HTML 解析;常用于首屏逻辑、早期初始化
- async/defer/module:决定下载与执行时机,影响首屏性能
- 执行后续逻辑:发起 XHR/Fetch/WebSocket,操作 DOM/CSS,驱动交互和数据更新
9.5 回流(Reflow)与重绘(Repaint)区别?
答案要点:
- 回流:布局信息变化(尺寸/位置/结构/字体大小等)→ 重新计算布局 → 之后一般还要重绘和合成,开销更大
- 重绘:仅视觉样式改变(颜色、背景等)但不影响布局 → 只需重新绘制
- 优化方向:减少不必要回流、批量 DOM 操作、使用 transform/opacity 动画、合理拆分图层等
9.6 后续访问为什么快?(性能与缓存)
答案要点:
- HTTP 缓存:强缓存(max-age)直接用本地;协商缓存(ETag/Last-Modified)返回 304
- 连接复用:HTTP/2/HTTP/3 多路复用、头部压缩
- Service Worker(若有):拦截请求,走自定义缓存策略甚至离线访问
9.7 极简 10 句版(快速口述)
- 输入 URL,浏览器解析协议、域名、端口、路径
- DNS 解析:查缓存 → 本地 DNS → 根/TLD/权威 DNS,得到 IP
- TCP 三次握手建立连接
- HTTPS 进行 TLS 握手:验证证书、协商密钥
- 发送 HTTP 请求(GET /),服务器返回 HTML
- HTML 解析构建 DOM 树(遇到同步 script 会阻塞)
- 加载 CSS 构建 CSSOM,DOM + CSSOM → Render Tree
- 布局(Layout)计算元素位置尺寸,绘制(Paint)生成绘制列表
- 分层、栅格化、合成(Compositing),首屏渲染完成
- JS 执行、异步请求、事件循环持续响应交互,触发回流/重绘更新页面
十、性能优化建议
10.1 DNS 优化
- 使用 DNS 预解析:
<link rel="dns-prefetch" href="//www.example.com"> - 减少域名数量(减少 DNS 查询次数)
- 使用 CDN 加速 DNS 解析
10.2 网络连接优化
- 使用 HTTP/2 或 HTTP/3(多路复用、头部压缩)
- TCP 预连接:
<link rel="preconnect" href="https://www.example.com"> - 使用 CDN 就近访问,减少延迟
10.3 资源加载优化
- 关键资源优先:内联关键 CSS,延迟非关键 CSS
- JS 优化:
- 使用
defer或async避免阻塞解析 - 代码分割、按需加载
- Tree Shaking 减少体积
- 使用
- 图片优化:
- 使用 WebP、AVIF 等现代格式
- 懒加载(
loading="lazy") - 响应式图片(
srcset)
10.4 渲染优化
- 减少回流/重绘:
- 批量 DOM 操作(使用 DocumentFragment)
- 使用
transform、opacity做动画(触发合成层) - 避免频繁读取布局属性(如
offsetWidth)
- CSS 优化:
- 避免深层嵌套选择器
- 减少
@import(阻塞渲染) - 使用
will-change提示浏览器优化
10.5 缓存策略
- HTTP 缓存:合理设置
Cache-Control、ETag - Service Worker:实现离线缓存、后台更新
- 浏览器缓存:利用 LocalStorage、SessionStorage、IndexedDB
10.6 代码层面优化
- 首屏优化:
- SSR(服务端渲染)或 SSG(静态生成)
- 骨架屏、占位符
- 懒加载:路由懒加载、组件懒加载
- 防抖/节流:优化事件处理频率