现代浏览器的工作原理(四)

布局

  在构建呈现树的过程中,浏览器创建的呈现器(框架)并不包含DOM元素的位置和大小信息。计算DOM元素的位置和大小信息的过程称为”布局”或者”重排”。
  布局是一个递归的过程,它从根呈现器(对应于根元素<html>)开始递归部分或者整个呈现树,为需要计算的呈现器计算位置和几何信息。

dirty位系统

  为了避免页面每个细小的更改都造成浏览器重新布局整个页面,浏览器引入了dirty位系统。当呈现器需要被重新布局时,则将其dirty位设置为true。

布局过程

  布局过程通常具有以下几种模式:

  1. 父呈现器确定自己的宽度;
  2. 父呈现器依次处理子呈现器,并且执行以下操作:(1)放置子呈现器(设置x,y坐标);(2)在子呈现器需要被重新布局时调用子呈现器的布局方法。
  3. 父呈现器根据子呈现器的累加高度以及内外边距的高度来计算自身的高度,该值可被其父呈现器使用。
  4. 设置dirty位的值为false。

处理换行

  如果在布局处理过程中呈现器需要换行,该呈现器会停止当前布局并告知其父呈现器需要换行。父呈现器会创建一个新的子呈现器并调用其布局方法来呈现新的一行。

优化布局

  浏览器会缓存呈现器的尺寸和位置信息,当下次布局需要这些信息时,浏览器无需重新计算呈现其的位置和大小信息。如果只是呈现树的部分子树发生了修改,则浏览器只会对当前修改的子树进行重新布局。

绘制

  绘制的目的是浏览器将呈现器中的内容在屏幕上显示出来。在绘制阶段,浏览器会遍历呈现树,调用呈现器的paint方法来绘制呈现器中的内容。整个绘制工作依赖于用户界面基础组件完成。

绘制顺序

  浏览器的绘制顺序就是元素进入堆栈样式上线文的顺序,块呈现器的绘制顺序如下:

  1. 背景颜色。
  2. 背景图。
  3. 边框。
  4. 子元素。
  5. 轮廓。

优化绘制

  Firefox会遍历整个呈现树,为绘制的矩形创建一个显示列表。该列表按照浏览器的绘制顺序存储了与所绘制的矩形相关的所有呈现器。采用这种方式之后,浏览器每次重绘时只须遍历一次呈现树,而不需要为了绘制所有的背景、边框而多次遍历呈现树。提升了浏览器的性能。
  Webkit在重绘之前,会将原来的矩形另存为一张位图,每次绘制只绘制新旧矩形之前的差异部分。
  在页面发生变化时,浏览器会尽量作出最小的响应。与布局过程一样,浏览器只会重绘当前发生更改的呈现子树。

呈现引擎线程

  浏览器的呈现引擎采用单线程。除了网络操作外几乎所有的操作都是在单线程中进行。在Firefox和Safari中,该线程就是浏览器的主线程;在Chrome中,该线程是标签进程的主线程。

事件循环

  浏览器的主线程是一个事件循环,该事件循环是一个无限循环,永远处于侦听状态。当事件发生时(如布局和绘制事件)浏览器就会及时侦听到该事件并处理。