前言
之前我写过的文章一文解答web性能优化中提及了重排和重绘的性能消耗问题,那时候只是一笔带过,而我只是大概的了解而已。为了下一阶段的学习对它能有更清晰的认知,我又重新去看了这一块的内容。
一、浏览器的渲染进程
浏览器的进程有很多:如Browser进程(主线程)、渲染进程、GPU进程和插件进程。
这里主要讲一下渲染进程,这是和前端的工作息息相关的。
渲染进程又划分了多个线程:
1、GUI线程
负责渲染页面。我们所知道的解析HTML和CSS,构建DOM树、CSSOM树和render树和绘制布局的过程都在这一个线程中进行。只要界面需要重绘或者重排时,就会执行该线程。
2、JS引擎线程
负责解析并运行JS代码。值得注意的是,它与GUI线程是互斥的关系。当JS代码执行的时间过长,会阻塞页面渲染。这也就是为什么我们常常把JS代码放到代码的末端执行的原因。
3、事件触发线程
这个线程并不属于JS引擎线程中,而是单独的一条线程,负责控制事件循环,就是我们常说的event loop。在事件触发时,会将对应的事件添加到处理队列的对尾,等待Js引擎处理。
4、计时器触发线程
这个线程同样时不属于Js引擎线程的。负责计时,计时完毕后,将事件添加到事件队列,等待Js引擎处理。
5、异步HTTP请求线程
在XMLHttpRequest连接后,浏览器会创建一个异步请求线程来监测请求的状态变更。
二、页面渲染过程
先放一个非常常见的图,能够快速看懂这个过程。
1、 解析HTML和CSS
HTML解析过程是一个深度遍历的过程,它会遍历一个节点下的所有子节点才会开始解析下一个兄弟节点,最后构建出一个DOM树。
CSS同样也会解析并构建成为CSSOM树。
2、构建render树
第二步,浏览器会拿着已经构建好的DOM和CSSOM来构建一个新的树,称之为render树。
值得一提的是,这个过程会筛选掉那些不可视的元素,如含有“display:none”的元素。
另外,那种脱离文档流的元素在render树和Dom树的位置也不尽相同。
所以,render树和Dom树并不是一一对应的,只能说他们是有着对应关系的。
3、布局和绘制
到了这个阶段,渲染树的节点是没有位置和大小的,计算元素的位置和大小的这个过程,称之为布局(layout)。
而之后根据渲染树内容绘制在浏览器上。
这个过程比较消耗性能,所以浏览器会试着用最小的响应来应对元素的变化,如当元素的颜色发生变化时,并不会引起重新布局,而只是重新绘制而已。只有在Dom节点发生较大的变化,才会引发重新布局,也就是我们常说的重排,也叫回流。
结语
重看了一遍相关的知识,觉得自己对浏览器的认识再次加深了一些。为什么各大框架都喜欢用虚拟DOM?其实答案就是为了减少重排和重绘带来的性能问题,不过仅仅是为了解决更新的性能问题,毕竟第一次挂载的时候,仍要深度遍历我们所写的HTML。