关于浏览器的页面渲染原理,是一个比较基础的问题,但还是很重要的,因为这会引申出一系列性能优化的问题。
我们使用的浏览器,主要依靠浏览器中的运行的最核心的程序,也就是我们平时所说的浏览器内核,浏览器内核最主要的两部分:渲染引擎和Js引擎。渲染引擎负责页面的渲染,展示;Js引擎负责解析Javascript语言,执行javascript语言来实现网页的动态效果
目前市场主流的浏览器内核是不同的,在这里以一张表格来呈现
对于前端来说,最熟悉最友好的肯定是Chrome浏览器,它的渲染引擎是Webkit,JS引擎是V8引擎,这篇文章就来聊一聊Webkit 的渲染过程(其它的也只是稍有不同啦):
可分为四个步骤:
解析Html,CSS:解析Html生成DOM树,解析CSS生成CSS规则树【注意我们由图中可以看出 这两者的解析是同时进行的 但是生成的Dom树需要等到CSS解析完才能进行下一步,所以CSS的加载是会阻塞渲染的】
构建Render树 :根据Dom树和CSS规则树构建出RenderTree(渲染树)【注意:并不是简单的将二者合并,渲染树只会包括需要展示的节点及其样式信息,比如display:none的节点就不会放入Render树中以及 float或者 position:absolute的元素,因为它们脱离了正常的文档流,构造Render树的时候会针对它们实际的位置进行构造】
布局Render树:我们从得到的渲染树,计算出每个元素在视口内的确切位置和尺寸,最终输出的是一个box盒模型
绘制Render树 :在绘制阶段,渲染引擎会遍历Render树,触发Paint事件,输出为最终屏幕上的像素
大致过程就是这样,读完可能会有疑问:那Js呢?要是解析html的时候遇到Js呢,Js不是也可以操作页面中的Dom元素吗?
先来看一张图吧,从进程和线程的角度再来理解浏览器
可以看到,浏览器是包含多个进程的,最下面的渲染进程其实就是我们开始提到的浏览器内核,渲染引擎就是在GUI渲染线程中运行,Js引擎就是在Js引擎线程中运行。我们知道JavaScript是操作dom的,如果GUI线程和Js引擎线程可以同时运行,那么就可能会产生冲突,所以浏览器规定这两个线程是互斥的,当 JavaScript 引擎执行时 GUI渲染 线程会被挂起,并被保存在一个队列中等到Js引擎线程空闲时立即被执行,所以从底层上回答了之前的问题,html的解析是会被Js所阻塞的,直到Js执行完成。
浏览器页面渲染机制分析完了,同时问题也就产生了,如果解析Html的过程中Js的执行时间过长,必然会导致首屏加载速度过慢,以及如果执行Js对页面Dom元素有较多的操作和改变会频繁的触发回流与重绘,这都会造成性能下降。后续文章将会从如何减少回流与重绘的次数和关键渲染路径的角度来说一说前端性能优化。
感谢阅读 欢迎指正~
文章参考:
你不知道的浏览器页面渲染机制
从 8 道面试题看浏览器渲染过程与性能优化
前端必会!四步带你吃透浏览器渲染基本原理