1、简单描述一下浏览器渲染页面机制
答:浏览器(Chrome浏览器为例)渲染页面主要依赖的是JS引擎(V8引擎)和渲染引擎(Blink引擎)
- V8 引擎:复杂JS的解析执行(逻辑处理、事件绑定、操作DOM);
- Blink引擎:负责页面合成渲染(解析HTML/CSS、构建DOM/CSSOM、布局绘制)。
扩展:JS 引擎和渲染引擎具体的交互操作(以 Chrome 浏览器为例)
1. 资源加载(由网络进程完成)
- 用户输入RUL,浏览器主进程网络进程发起请求;
- 下载HTML、CSS、JS、图片等资源;
- HTML送入渲染进程;
2. HTML解析 → DOM构建 (Blin引擎)
- Blink引擎开始解析HTML,构建DOM树;
- 如果遇到 script 标签,会暂停HTML解析,转而交给V8引擎执行JS;【问题1】
3. 执行 执行 JavaScript(V8引擎)
- Blink 调用 V8 引擎执行 JS 代码:
修改DOM(document.body.appendChild());
执行逻辑、绑定事件、操作DOM;
- JS执行过程中可能还会再次触发DOM、样式等变化(比如增加class、修改style);【问题2】
4. CSS解析&构建CSSOM (Blink引擎)【问题3】
- Blink引擎同步或者异步解析CSS,构建CSSOM样式规则树;
- CSS也可能受到JS动态影响,比如(添加Class、修改style);
- 内联样式( 标签)在遇到时会立即被解析,构建 CSSOM 样式树;
- 外部 CSS()会触发浏览器通过网络线程异步下载 CSS 文件,下载过程中不会阻塞 HTML 的解析;
- 一旦 CSS 文件下载完成,浏览器会立即解析该 CSS 文件并构建 CSSOM。
5. 构建渲染树(Render Tree) 【Blink引擎】
- Blink把DOM树和CSSOM树合并,生成渲染树(只包含可见节点);【问题4】【问题5】
- 每个渲染树节点包含元素的可视样式信息;【问题6】
6. 布局(Layout/Reflow)
- Blink根据每个渲染树计算出具体位置和尺寸;
- 这个过程受JS和样式的影响(比如JS操作了DOM或者修改了样式,就会可能引起重排、重绘);
7. 绘制(Painting)
- Blink引擎将每个节点转换成绘制指令,比如背景、边框、文本、引用等;
8. 合成图层(Compositing)
- Blink会将不同图层的绘制指令交给合成线程;
- 合成线程将图层合成最终的页面图像;
- 使用GPU(硬件加速)渲染到屏幕。
问题解答:
问题1: script 标签上异步加载属性 async、defer 属性,浏览器会怎么做?
答:浏览器遇到script标签一般是同步执行的,会暂停HTML解析,会立即下载并执行脚本;但如果script标签上async或者defer属性,则会变成异步的,但async和defer执行时机不同。
- async属性: 当浏览器遇到携带async属性的script标签时,不会停止HTML解析,主线程会调用网络线程下载脚本,当脚本下载完成之后,会立即暂停HTML解析,执行下载的JS脚本,JS脚本执行完毕后会接着解析HTML;
- defer 属性: 当浏览器遇到带 defer 属性的 script 标签时, 不会停止HTML的解析,主线程会调用网络线程下载JS脚本;等HTML解析完毕后才会执行下载完的JS脚本(在 DOMContentLoaded 之前)。
// DOMContentLoaded:是在 document(文档对象上挂载着),在window对象上也可以获取到,因为事件会冒泡到window上
document.addEventListener('DOMContentLoaded',()=>{
// 表示文档解析完成但资源未必加载完毕。
console.log('DOM 完全加载和解析完成');
})
- 内联脚本: 对内联脚本添加 async/defer 属性,不生效;内联脚本不需要单独下载,同步执行,会阻塞HTML解析。
问题 2: 如果在解析执行 JS 脚本时,遇到 DOM 操作或者样式的修改,是先把 JS 脚本执行完毕后,再去调用渲染引擎,操作 DOM 和样式?还是先调用渲染引擎操作 DOM 和样式完成后再去接着执行 JS?
答:浏览器在解析JS的过程中如果遇到DOM修改或修改样式,不会立即停止JS的执行去触发渲染;而是等JS完全执行完毕后,主线程才会调用渲染线程,进行样式计算,布局,绘制。 其中遇到DOM修改或样式修改时,浏览器会将这些操作记录到内存中DOM/CSSOM结构中,等JS执行完毕后,主线程才会根据DOM/CSSOM渲染被操作的节点。所以没 有先去渲染,但这些操作已经保存到内存中了,是可以通过JS获取到的。
问题 3: 为什么解析步骤是先解析 HTML、JS、然后最后是 CSS?
答:浏览器解析html文件时,是自上而下、逐行进行的,所以并没有JS和CSS谁先谁后解析的说法;但是在head标签中并不推荐吧 script标签放在link、style标签之前,否则可能出现渲染问题,所以在head标签中js脚本不建议有操作DOM/CSSOM的JS逻辑。如果有可以放在body标签后。
问题 4: 渲染引擎是如何合并 DOM 和 CSSOM 生成渲染树的,此时 JS 参与吗?
答:渲染树的生成是通过遍历DOM树和CSSOM样式树计算出每个节点的样式(如位置、大小、颜色等),生成的渲染树只保留了可是节点;而 JS 并不参与渲染树的合并,但如果JS中有DOM和CSS操作,浏览器会先标记DOM树和CSSOM树为脏状态,在下一帧渲染的时候会重新构建DOM树和CSSOM样式树("标记脏节点" + "部分更新")
问题 5: 为什么只包含可见节点? 如果 DOM 有变动,渲染树怎么更新?
答:渲染树只包含页面上要显示的节点,因为它的目标是生成屏幕上的像素,对于设置了display的元素,浏览器会直接跳过,不会将其加入渲染树中,这样可以避免无用节点参与后续的计算、布局、绘制等过程,节省了内存和减少了性能消耗。 当有DOM变动时,浏览器通过监听DOM和CSSOM变化,触发对应的更新;浏览器会对要更新的节点标记为“脏”节点,根据“脏”节点重新生成要更新的渲染树,最后根据新的渲染树绘制成页面。
问题 6:可视样式信息 是不是就是这个标签上携带的属性等信息? 答:这些可视信息不是标签上的属性,而是指每个元素最终参与渲染时所需要的视觉表现数据,包括颜色、尺寸、边距、字体、布局等信息也就是CSS计算后的样式信息(Computed Style)。