浏览器渲染
并行下载 vs. 渲染阻塞
这两者描述的是不同阶段的事情:
- 并行下载(网络层面)
<head><link rel="stylesheet" href="styles.css"> <!-- 开始下载 --><link rel="stylesheet" href="components.css"> <!-- 同时开始下载 --><script src="app.js"></script> <!-- 同时开始下载 -->
</head>
<body><img src="hero.jpg"> <!-- 同时开始下载 -->
</body>
浏览器行为:
· 遇到外部资源链接时,浏览器会立即开始下载
· CSS、JS、图片等资源可以并行下载(受域名并发数限制)
· 这是网络层面的并行性
- 渲染阻塞(渲染流程层面)
虽然CSS在下载,但浏览器的渲染流程被"冻结"了:
<head><link rel="stylesheet" href="styles.css"> <!-- 阻塞渲染 -->
</head>
<body><h1>这个内容要等CSS下载完才能显示</h1><!-- 即使HTML已经解析到这里,也不会渲染 -->
</body>
实际的时间线示例
假设:
· styles.css 需要 2 秒下载
· components.css 需要 3 秒下载
· HTML 解析只需要 0.1 秒
<!DOCTYPE html>
<html>
<head><link rel="stylesheet" href="styles.css"> <!-- 2秒 --><link rel="stylesheet" href="components.css"> <!-- 3秒 -->
</head>
<body><h1>页面内容</h1><script src="app.js"></script> <!-- 1秒 -->
</body>
</html>
时间线:
· T+0秒:开始解析HTML,发现 styles.css 和 components.css,立即并行开始下载
· T+0.1秒:HTML 解析完成,DOM 构建完成
· T+0.1秒 到 T+2秒:
· 两个CSS文件还在下载中
· 浏览器不能渲染页面(显示空白屏幕)
· 但下载过程在后台并行进行
· T+2秒:styles.css 下载完成
· T+3秒:components.css 下载完成
· T+3秒:所有CSS下载完成,浏览器开始构建CSSOM,然后合并渲染树,最终显示页面
为什么这样设计?
设计合理性:
- 避免重复工作:如果不等CSS就渲染,等CSS加载后又要重新计算样式、重新布局、重新绘制
- 保证一致性:用户看到的就是最终样式的页面
- 性能权衡:短暂的空白屏幕比闪烁的样式变化体验更好
对比JavaScript的阻塞:
<head><link rel="stylesheet" href="styles.css"> <!-- 阻塞渲染,但不阻塞HTML解析 --><script src="app.js"></script> <!-- 阻塞HTML解析,因此也间接阻塞渲染 -->
</head>
· CSS阻塞:只阻塞渲染,不阻塞HTML解析和DOM构建
· JS阻塞:阻塞HTML解析,因此也阻塞后续的渲染
实际验证
你可以自己测试一下:
<!DOCTYPE html>
<html>
<head><title>CSS阻塞测试</title><!-- 模拟一个慢速CSS --><link rel="stylesheet" href="/slow-css?delay=3000">
</head>
<body><h1 id="status">如果看到这段文字,说明渲染被阻塞了</h1><script>document.addEventListener('DOMContentLoaded', () => {console.log('DOMContentLoaded 触发 - DOM已构建完成');});window.addEventListener('load', () => {console.log('load 触发 - 所有资源加载完成');document.getElementById('status').textContent = '页面现在完全加载了';});</script>
</body>
</html>
你会观察到:
· DOMContentLoaded 很快触发(DOM构建完成)
· 但页面内容要等3秒后才显示(渲染被阻塞)
总结
阶段 行为 影响
遇到链接 立即开始并行下载 网络优化
CSS下载期间 阻塞页面渲染 避免FOUC
HTML解析 继续构建DOM 为后续渲染准备
CSS下载完成 立即构建CSSOM并渲染 一次性正确显示
所以"并行下载"和"渲染阻塞"并不矛盾——一个是网络资源加载策略,一个是用户体验保证策略。浏览器在后台高效加载资源的同时,在前台谨慎控制着内容的显示时机。