浏览器的工作原理

浏览器的组成

  • 用户界面- 包括地址栏、后退/前进按钮、书签目录等,也就是你所看到的除了用来显示你所请求页面的主窗口之外的其他部分
  • 浏览器引擎- 用来查询及操作渲染引擎的接口
  • 渲染引擎(浏览器内核)- 用来显示请求的内容,例如,如果请求内容为 html,它负责解析 html 及 css,并将解析后的结果显示出来
  • 网络- 用来完成网络调用,例如 http 请求,它具有平台无关的接口,可以在不同平台上工作
  • UI 后端- 用来绘制类似组合选择框及对话框等基本组件,具有不特定于某个平台的通用接口,底层使用操作系统的用户接口
  • JS 解释器- 用来解释执行 JS 代码
  • 数据存储- 属于持久层,浏览器需要在硬盘中保存类似 cookie 的各种数据,HTML5 定义了 Storage 技术,这是一种轻量级完整的客户端存储技术

主流的渲染引擎

浏览器的渲染引擎也叫排版引擎,或者是浏览器内核

主流的 渲染引擎 有

  • Chrome 浏览器: Blink 引擎(WebKit 的一个分支)。
  • Safari 浏览器: WebKit 引擎,windows 版本 2008 年 3 月 18 日推出正式版,但苹果已于 2012 年 7 月 25 日停止开发 Windows 版的 Safari。
  • FireFox 浏览器: Gecko 引擎。
  • Opera 浏览器: Blink 引擎(早期版使用 Presto 引擎)。
  • Internet Explorer 浏览器: Trident 引擎。
  • Microsoft Edge 浏览器: EdgeHTML 引擎(Trident 的一个分支)。

渲染引擎工作原理

渲染引擎解析的基本流程:

  • 解析 HTML 构建 DOM树,同时解析所有的 css 样式,构建 css 规则
  • 根据 DOM 树和 css 规则合并构建 渲染树
    • DOM 树上的节点没有样式的,渲染树的节点有样式的
    • 渲染树上的节点都是需要渲染的,所以渲染树上没有像head标签 或 display: none这样的元素,但是它们在 DOM 树中
  • 对渲染树进行布局,定位坐标和大小、确定是否换行、确定 position、overflow、z-index 等等,这个过程叫layoutreflow
  • 绘制渲染树,调用操作系统底层 API(UI Backend)进行绘图操作

webkit 内核工作流程

gecko 内核工作流程

重绘与回流

重绘与回流

回流(reflow): 又叫重排,当 render tree 中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。

重绘(repaint):当 render tree 中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如 background-color。

  1. 每个页面至少需要一次回流+重绘
  2. 回流必将引起重绘

回流什么时候发生?

  • 添加或者删除可见的 DOM 元素
  • 元素位置改变
  • 元素尺寸改变——边距、填充、边框、宽度和高度
  • 内容改变——比如文本改变或者图片大小改变而引起的计算值宽度和高度改变
  • 页面渲染初始化
  • 浏览器窗口尺寸改变(resize事件)发生时
var s = document.body.style
s.padding = '2px' // 回流+重绘
s.border = '1px solid red' // 再一次 回流+重绘
s.color = 'blue' // 再一次重绘
s.backgroundColor = '#ccc' // 再一次 重绘
s.fontSize = '14px' // 再一次 回流+重绘
// 添加node,再一次 回流+重绘
document.body.appendChild(document.createTextNode('abc!'))

聪明的浏览器

从上个实例代码中可以看到几行简单的 JS 代码就引起了 6 次左右的回流、重绘。而且我们也知道回流的花销也不小,如果每句 JS 操作都去回流重绘的话,浏览器可能就会受不了。所以很多浏览器都会优化这些操作,浏览器会维护 1 个队列,把所有会引起回流、重绘的操作放入这个队列,等队列中的操作到了一定的数量或者到了一定的时间间隔,浏览器就会 flush 队列,进行一个批处理。这样就会让多次的回流、重绘变成一次回流重绘。

虽然有了浏览器的优化,但有时候我们写的一些代码可能会强制浏览器提前 flush 队列,这样浏览器的优化可能就起不到作用了。当你向浏览器请求一些 style 信息的时候,就会让浏览器 flush 队列,比如:

  • offsetTop, offsetLeft, offsetWidth, offsetHeight
  • scrollTop/Left/Width/Height
  • clientTop/Left/Width/Height
  • width,height
  • 请求了 getComputedStyle(), 或者 IE 的 currentStyle

如何性能优化

减少回流与重绘的次数,就需要简单对渲染树的操作

  • 直接使用 className 修改样式,少用 style 设置样式
  • 让要操作的元素进行”离线处理”,处理完后一起更新
    • 使用 DocumentFragment 进行缓存操作,引发一次回流和重绘
    • 使用 display:none 技术,只引发两次回流和重绘
  • 将需要多次重排的元素,position 属性设为 absolute 或 fixed,这样此元素就脱离了文档流,它的变化不会影响到其他元素为动画的 HTML 元素,例如动画,那么修改他们的 CSS 是会大大减小 reflow