浏览器原理知识总结


1. 浏览器组成

  • 用户界面(User Interface)
    用户界面主要包括工具栏、地址栏、前进/后退按钮、书签菜单、可视化页面加载进度、智能下载处理、首选项、打印等。除了浏览器主窗口显示请求的页面之外,其他显示的部分都属于用户界面。
    用户界面还可以与桌面环境集成,以提供浏览器会话管理或与其他桌面应用程序的通信。

  • 浏览器引擎(Browser Engine)
    在用户界面和渲染引擎之间传送指令。

  • 渲染引擎(Rendering Engine)
    显示请求的内容。

  • 网络(Networking)
    网络调用,如http请求。

  • JavaScript解析器(JavaScript Interpreter)
    JavaScript解释器能够解释并执行嵌入在网页中的JavaScript(又称ECMAScript)代码。 为了安全起见,浏览器引擎或渲染引擎可能会禁用某些JavaScript功能,如弹出窗口的打开。

  • 显示后端(Display Backend)
    显示后端提供绘图和窗口原语,包括:用户界面控件集合、字体集合

  • 数据持久层(Data Persistence)
    数据持久层将与浏览会话相关联的各种数据存储在硬盘上。 这些数据可能是诸如:书签、工具栏设置等这样的高级数据,也可能是诸如:Cookie,安全证书、缓存等这样的低级数据。

2. 浏览器内核

浏览器 渲染引擎(内核) JS引擎
Chorme Webkit->Blink v8
FireFox Gecko SpiderMonkey
Safari Webkit JavaScriptCore
Opera Presto->Webkit->Blink JavaScriptCore
Edge EdgeHTML Chakra(for JavaScript)
IE Trident JScript(IE3.0-IE8.0)

3. 架构

现代浏览器多为多进程架构

  • Browser进程

    • 浏览器的主进程(负责协调、主控),该进程只有一个
    • 负责浏览器界面显示,与用户交互。如前进,后退等
    • 负责各个页面的管理,创建和销毁其他进程
    • 将渲染(Renderer)进程得到的内存中的Bitmap(位图),绘制到用户界面上
    • 网络资源的管理,下载等
  • 插件进程

    • 每种类型的插件对应一个进程,当使用该插件时才创建
  • GPU进程

    • 该进程也只有一个,用于图形绘制等等
  • 渲染进程

    • 即通常所说的浏览器内核(Renderer进程,内部是多线程)
    • 每个Tab页面都有一个渲染进程,互不影响
    • 主要作用为页面渲染,脚本执行,事件处理等
  • 网络进程

    • 负责发起和接受网络请求

4. 渲染进程

浏览器渲染进程是多线程模型,主要包含如下线程:

  • GUI渲染线程

    • 解析HTML,CSS,构建DOM树、构建render树,布局和绘制等
    • 界面重绘(Repaint)或回流(reflow)
  • JS引擎线程

    • 处理JavaScript程序
    • JS引擎一直等待着任务队列中任务的到来,然后加以处理
    • 和GUI渲染线程是互斥的
  • 事件触发线程

    • 属于浏览器而不是JS引擎,用来控制事件循环,并且管理着一个事件队列(task queue)
    • 当JS引擎执行如setTimeOut代码块时,或者是其他的如网络异步请求、鼠标点击等时,会将对应任务添加到事件线程中。当对应的事件符合触发条件被触发时,该线程会把事件添加到待处理的事件队列中,等待JS引擎空闲时处理。
  • 定时器线程

    • setInterval与setTimeout所在线程。计时完毕后,将对应事件添加到事件队列中,等待JS引擎空闲时处理。
  • 异步网络请求线程

    • 处理网络请求,如果设置有回调函数,异步线程就产生状态变更事件,将这个回调再放入事件队列中。等待JS引擎空闲时处理。

5. 页面渲染流程

  1. HTML 解析器解析 HTML 文档,生成 DOM 树 (DOM Tree)
  2. CSS 解析器解析 CSS 文档,生成 CSSOM (CSS Object Model)
  3. 将DOM树和CSSOM结合,生成渲染树(Render Tree)
  4. 根据渲染树来布局(Layout),以计算每个节点的几何信息
  5. 将各个节点绘制(painting)到屏幕上

6. 回流和重绘

回流(reflow)

Render Tree中部分或全部元素的几何尺寸发生改变,浏览器重新计算元素的几何属性并调整布局的过程,也称重排

💡触发场景:

  • 页面首次渲染
  • 浏览器的窗口尺寸变化
  • 元素的位置/尺寸/内容/字体大小发生变化
  • 添加或删除可见的DOM元素
  • 查询一些属性或方法
    • clientTop、clientLeft、clientWidth、clientHeight
    • offsetTop、offsetLeft、 offsetWidth、offsetHeight
    • scrollTop、scrollLeft、scrollWidth、scrollHeight
    • scrollIntoView()、scrollIntoViewIfNeeded()、getComputedStyle()、getBoundingClientRect()、scrollTo()

重绘(repaint)

Render tree中的一些元素只发生样式的改变并不影响它在文档流中的位置时,浏览器不需重新计算元素的几何属性、直接为元素绘制新的样式的过程。

💡触发场景:

  • 回流
  • 一些CSS属性的改变
    • color、border-style、visibility、background、text-decoration、background-image、background-position、background-repeat、outline-color、outline、outline-style、border-radius、outline-width、box-shadow、background-size

关系

回流必将引起重绘,重绘不一定会引起回流。

7. 浏览器缓存机制

浏览器的缓存机制,通常是指我们常说的HTTP缓存机制,主要分为协商缓存强缓存,缓存机制的运行流程如下:

  • 浏览器在进行HTTP请求前,会先向缓存中查找该请求结果,根据该缓存结果的缓存标识 ExpiresCache-Control 判断是否命中强缓存,是则直接使用该缓存结果,不会发请求到服务器。
  • 如果没有命中强缓存或强缓存已失效,浏览器会发送一个请求到服务器,通过携带缓存标识Last-Modified / If-Modified-SinceEtag / If-None-Match 验证资源是否命中协商缓存,如果命中,服务器会返回304,依然是从缓存中读取资源
  • 如果没有命中或协商缓存失效,服务器会重新返回完整的资源

附:

  • ExpiresHTTP/1.0中的控制字段,是绝对值,受限于本地时间;Cache-ControlHTTP/1.1中的字段,记录的时间是相对值,Cache-Control的优先级高于Expires
  • 浏览器读取缓存会优先从内存缓存中读取(from memory cache),其次从硬盘读取(from disk cache)
  • 控制协商缓存的字段 Etag / If-None-Match 的优先级比 Last-Modified / If-Modified-Since

8. V8垃圾回收机制

V8采用的是分代式回收, 即将堆分为新生代和老生代两类,新生代中存放的是生存时间短的对象,老生代中存放的生存时间久的对象。V8分别使用两个不同的垃圾回收器来实施垃圾回收。

  • 新生代垃圾回收器 - Scavenge
  • 老生代垃圾回收器 - Mark-Sweep & Mark-Compact

针对新生代堆,Scavange算法将其分为两部分,分别叫from空间和to空间,工作过程就是将from空间中存活的活动对象复制到to空间中,并将这些对象的内存有序的排列起来,然后将from空间中的非活动对象的内存进行释放,完成之后,将from空间和 to 空间进行互换。
V8引擎采用了对象晋升策略,在下一次垃圾回收时,已经进行过一次垃圾回收依然还存活的对象或to空间的内存占比超过25%,对象会被移动到老生代区中。
之所以有25%的内存限制是因为to空间在经历过一次Scavenge算法后会和from空间完成角色互换,会变为from空间,后续的内存分配都是在from空间中进行的,如果内存使用过高甚至溢出,则会影响后续对象的分配。

针对老生代堆,采用的是 标记-清除(Mark-Sweep)标记-整理(Mark-Compact)算法。标记-清除就是从一组根元素开始,递归遍历这组根元素(遍历调用栈),在这个遍历过程中,能到达的元素标记为活动对象,然后在第二次遍历过程中清除未被标记的对象(非活动对象)。清除算法后,会产生大量不连续的内存碎片,而碎片过多会导致大对象无法分配到足够的连续内存。于是又产生了标记-整理算法,这个标记过程仍然与标记-清除算法里的是一样的,但后续不是对非活动对象进行清理,而是让活动对象都向一端移动,然后直接清理掉端边界以外的内存,从而让存活对象占用连续的内存块。

参考文档

  1. 现代浏览器架构漫谈
  2. 现代浏览器工作原理(一)
  3. 送你18道浏览器面试题
  4. 11道浏览器原理面试题
  5. 深入理解Chrome V8垃圾回收机制
  6. 彻底理解浏览器的缓存机制
  7. 一文看懂Chrome浏览器运行机制

文章作者: Snail-Lu
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Snail-Lu !
  目录