请说说从输入 URL 到页面渲染完成的全过程
核心概括
- 网络连接建立阶段(DNS、TCP、TLS)
- 资源解析与构建阶段(DOM、CSSOM、预加载扫描)
- 页面渲染阶段(渲染树、布局、绘制、合成)
具体流程
URL 输入
│
├─ 阶段一:DNS 解析(域名 → IP)+ 建立连接
│ 浏览器缓存 → hosts → 本地DNS → 根DNS → TLD → 权威DNS
│ ① TCP 三次握手(SYN/ACK): 确保客户端正常连接服务端
│ ② TLS 握手(HTTPS 才需要):保障数据传输的加密性
│ ③ 发送 HTTP 请求,获取 HTML/CSS/JS 资源
├─ 阶段二:资源解析与构建阶段
① 解析 HTML → DOM Tree
② 解析 CSS → CSSOM Tree
③ 合并 → Render Tree
├─ 阶段三:资源解析与构建阶段
④ Layout(布局计算)
⑤ Paint(绘制)
⑥ Composite(合成显示)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
第一阶段:网络连接建立 (DNS, TCP, TLS)
第二阶段:解析与构建
预加载扫描器 (Preload Scanner):这是浏览器的优化机制。当主线程被 JS 阻塞时,扫描器会在后台提前下载后续需要的 CSS 和 JS,减少等待时间。
阻塞效应:
- CSS 不阻塞 DOM 构建,但阻塞 JS 执行(因为 JS 可能查询样式)。
- 没有 async/defer 的 JS 会完全阻塞 DOM 构建。
DOM 与 CSSOM:这是两棵独立的树,它们随后将被合并。
第三阶段:渲染阶段 (Rendering Pipeline)
重排 (Reflow/Layout):当元素的尺寸、位置发生变化时触发,成本很高(例如:未定义尺寸的图片加载完成后撑开页面)。
重绘 (Repaint):当元素外观变化但不影响布局时触发(例如:改变背景色)。
合成 (Composite):将页面分为多个层(Layer),利用 GPU 进行处理。使用 transform 和 opacity 动画效率高,因为它们只触发合成,跳过布局和绘制。
浏览器多进程模型
单进程
为什么不是单进程: 10. 不稳定早期浏览器:一个复杂的JS或者插件意外报错就会导致整个浏览器崩溃。 11. 不流畅:所有页面的渲染模块、JavaScript 执行环境以及插件都是运行在同一个线程中的,就会导致运行效率低。
多进程
Chrome 的页面是运行在单独的渲染进程中的,同时页面里的插件也是运行在单独的插件进程之中,而进程之间是通过 IPC 机制进行通信(如图中虚线部分)。
渲染层性能优化思路
渲染优化思路围绕任务执行时长来评估。
任务是指浏览器执行的任何独立工作。这包括呈现、解析 HTML 和 CSS、运行您编写的 JavaScript 代码,以及您无法直接控制的其他事项。网页的 JavaScript 是浏览器任务的主要来源。

减轻主进程压力
主线程一次只能处理一个任务。任何耗时超过 50 毫秒的任务均算作“耗时”。如果用户尝试在长时间的任务或渲染更新期间与页面互动,浏览器必须等待处理该互动,从而导致延迟。

为了避免这种情况,请将每个耗时较长的任务划分为多个小任务,每个小任务的运行时间较短。这称为拆分长任务。


拆分任务可让浏览器有更多机会响应其他任务之间优先级较高的工作,包括用户互动。这样可以更快地进行交互,否则用户在浏览器等待长时间任务完成时可能会注意到延迟。

任务管理策略
JavaScript 将每个函数视为单个任务,因为它使用“运行到完成”的任务执行模式。 这意味着,一个调用了多个其他函数的函数(如以下示例)必须一直运行到所有被调用的函数完成为止,这会导致浏览器速度变慢:
function saveSettings () { //This is a long task.
validateForm();
showSpinner();
saveToDatabase();
updateUI();
sendAnalytics();
}
2
3
4
5
6
7

手动推迟代码执行: 12. 将相关函数传递给 setTimeout() 来推迟某些任务的执行 13. 还可以使用 requestIdleCallback() 拆分工作,但它会以最低优先级调度任务,并且仅在浏览器空闲期间调度任务,这意味着,如果主线程特别繁忙,使用 requestIdleCallback() 调度的任务可能永远无法运行。 14. React Schedule、Chrome Scheduler API..