浏览器引擎以及渲染原理
2021.03.31 Wed

一个典型的浏览器有一个渲染引擎和一个独立的 JavaScript 引擎,因此浏览器内核可以分成两个部分,渲染引擎和 JS 引擎。但后来 JS 引擎越来越独立,内核就倾向于单指渲染引擎。而同一个网页在不同浏览器之间的差异就是不同浏览器使用的不同内核造成的。

浏览器引擎

排版引擎(layout engine),也称为浏览器引擎(browser engine)、页面渲染引擎(rendering engine)或样版引擎,它是一种软件组件,负责获取标记式内容(如 HTML、XML 及图像文件等等)、整理信息(如 CSS 及 XSL 等),并将排版后的内容输出至显示器或打印机。所有网页浏览器、电子邮件客户端、电子阅读器以及其它需要根据表示性的标记语言(Presentational markup)来显示内容的应用程序都需要排版引擎。

著名引擎:

  • Mozilla 开放源代码项目的网页浏览器引擎 Gecko,被 Mozilla 代码库中的各种产品所使用,其中包括 Firefox 网页浏览器、Thunderbird 电子邮件客户端和 SeaMonkey 网络包。Goanna 是 Gecko 的一个分支。
  • KDE 的开放源代码 KHTML 引擎在 KDE 的 Konqueror 网页浏览器使用,后来成为 WebKit 的基础,WebKit 是 Apple Safari 和早期 Google Chrome 网页浏览器的引擎。
  • Google 最初使用 WebKit 用于 Chrome 浏览器,但最终将其分支为自行建构的 Blink 引擎。所有以 Chromium 为基础的浏览器都使用 Blink,使用 CEF(英语:Chromium Embedded Framework),Electron 或任何其他 Chromium 嵌入式框架构建的应用程序也是如此。
  • Internet Explorer 的网页浏览器引擎 Trident,被 Microsoft Windows 平台的许多应用程序如 Outlook Express、某些版本的 Microsoft Outlook 和 Winamp、RealPlayer 中的迷你浏览器所使用。Trident 已经被 EdgeHTML 所取代,2019 年 EdgeHTML 被 Blink 取代。
  • Opera 软件公司的专有的 Presto 引擎被授权给其他许多软件供应商,也在 Opera 浏览器所使用,直到 2013 年被 Blink 取代。

JavaScript 引擎

JavaScript 引擎是一个专门处理 JavaScript 脚本的虚拟机,一般会附带在网页浏览器之中。

著名引擎:

  • Rhino,由 Mozilla 基金会管理,开放源代码,完全以 Java 编写。
  • SpiderMonkey,第一款 JavaScript 引擎,早期用于 Netscape Navigator,现时用于 Mozilla Firefox。
  • V8,开放源代码,由 Google 丹麦开发,是 Google Chrome 的一部分。
  • JavaScriptCore,开放源代码,用于 Safari。
  • Chakra (JScript 引擎),用于 Internet Explorer。
  • Chakra (JavaScript 引擎),用于 Microsoft Edge。

浏览器引擎前缀

浏览器厂商们有时会给实验性的或者非标准的 CSS 属性和 JavaScript API 添加前缀,这样开发者就可以用这些新的特性进行试验,同时(理论上)防止他们的试验代码被依赖,从而在标准化过程中破坏 web 开发者的代码。开发者应该等到浏览器行为标准化之后再使用未加前缀的属性

主流浏览器引擎前缀:

  • -webkit- (谷歌,Safari,新版 Opera 浏览器,以及几乎所有 iOS 系统中的浏览器(包括 iOS 系统中的火狐浏览器);基本上所有基于 WebKit 内核的浏览器)
  • -moz- (火狐浏览器)
  • -o- (旧版 Opera 浏览器)
  • -ms- (IE 浏览器 和 Edge 浏览器)

浏览器渲染原理

Web 页面运行在各种各样的浏览器当中,浏览器载入、渲染页面的速度直接影响着用户体验,而页面渲染就是浏览器将 html 代码根据 CSS 定义的规则显示在浏览器窗口中的这个过程。

  • HTML 代码转化成 DOM
  • CSS 代码转化成 CSSOM(CSS Object Model)
  • 结合 DOM 和 CSSOM,生成一棵渲染树(包含每个节点的视觉信息)
  • 生成布局(flow),即将所有渲染树的所有节点进行平面合成
  • 将布局绘制(paint)在屏幕上

"生成布局"(flow)和"绘制"(paint)相对更加耗时,合称为"渲染"(render)。

重排和重绘

网页生成的时候,至少会渲染一次。用户访问的过程中,还会不断重新渲染。
以下三种情况,会导致网页重新渲染。

  • 修改 DOM
  • 修改样式表
  • 用户事件(比如鼠标悬停、页面滚动、输入框键入文字、改变窗口大小等等)

重新渲染,就需要重新生成布局重新绘制。前者叫做"重排"(reflow),后者叫做"重绘"(repaint)。
需要注意的是,"重绘"不一定需要"重排",比如改变某个网页元素的颜色,就只会触发"重绘",不会触发"重排",因为布局没有改变。但是,"重排"必然导致"重绘",比如改变一个网页元素的位置,就会同时触发"重排"和"重绘",因为布局改变了。

网页渲染效率

重排和重绘会不断触发,这是不可避免的。但是,它们非常耗费资源,是导致网页性能低下的根本原因。
提高网页性能,就是要降低"重排"和"重绘"的频率和成本,尽量少触发重新渲染

CSS

  • 避免使用 table 布局。
  • 尽可能在 DOM 树的最末端改变 class。
  • 避免设置多层内联样式。
  • 将动画效果应用到 position 属性为 absolute 或 fixed 的元素上。
  • 避免使用 CSS 表达式(例如:calc())。

JavaScript

  • 避免频繁操作样式,最好一次性重写 style 属性,或者将样式列表定义为 class 并一次性更改 class 属性。
  • 避免频繁操作 DOM,创建一个 documentFragment,在它上面应用所有 DOM 操作,最后再把它添加到文档中。
  • 也可以先为元素设置 display: none,操作结束后再把它显示出来。因为在 display 属性为 none 的元素上进行的 DOM 操作不会引发回流和重绘。
  • 避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。
  • 对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流。

参考链接:

检测到页面内容有更新,是否刷新页面