这篇文章上次修改于 335 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

深入理解浏览器的进程与线程

当我们双击打开应用程序时,为什么点两下就能打开呢?到界面展示出来中间发生了什么呢?

其实我们双击的是一个程序的启动文件,我们在windows系统中安装完一个应用程序后,可以在对应的安装目录下看见整个程序的结构,一般在根目录下就能看到一个启动文件,当双击后,会像操作系统申请内存资源来运行该程序,分配者是CPU,而这个内存资源就是分配给了这个应用程序的主进程,控制着整个程序的运行。一个应用可有一个或多个相互独立且互不资源共享(互不影响)的进程,而每个进程又需一个或多个线程来完成用户需要的操作,线程之间也是相互独立的,但可以相互共享数据资源。

可以将进程比作一个个不同的工厂,每个工厂需要一定面积的地皮来支持整体的运作,这就像CPU分配的内存空间,那工人就是一个个线程,都有各自的工作,但他们可以相互沟通,也就是线程间共享数据。这样说大家应该不会再把进程和线程弄混淆了吧,下面通过浏览器仔细来说说两者与浏览器是怎么回事。

浏览器的进化历程

1990年,蒂姆·伯纳斯·李开发了第一个网页浏览器WorldWideWeb,后改名为Nexus。WorldWideWeb浏览器支持早期的HTML标记语言,功能比较简单,只能支持文本、简单的样式表、电影、声音、图片等资源的显示。
1993年,马克·安德森领导的团开发了一个真正有影响力的浏览器Mosaic,这就是后来世界上最流行的浏览器Netscape
Navigator。
1995年,微软推出了闻名于世的浏览器Internet Explorer。第一次浏览器大战开始,持续两年
1998年,Netscape公司开放Netscape Navigator源代码,成立了Mozilla基金会。第二次浏览器大战开始,持续八年
2003年,苹果公司发布了Safari浏览器。
2004年,Netscape公司发布了著名的开源浏览器Mozilla Firefox
2005年,苹果公司开源了浏览器中的核心代码,基于此发起了一个新的开源项目WebKit(Safari浏览器的内核)。
2008年, Google公司已WebKit为内核,创建了一个新的浏览器项目Chromium。以Chromium为基础,谷歌发布了Chrome浏览器。至于这两者的关系,可以简单地理解为:Chromium为实验版,具有众多新特性;Chrome为稳定版。

浏览器的组成

组成

和前端打交道最多的就是浏览器了,可分为7个主要部分:

  • 用户界面(User Interface):浏览器中菜单栏、地址栏、向前/回退按钮、书签目录等除了页面显示窗口外的所有地方都属于用户界面。
  • 浏览器引擎(Browser Engine):浏览器引擎是各个组件之间通信的核心,它在用户界面与渲染引擎间传递指令,为渲染引擎提供接口,将用户界面上的给定的网址、用户浏览器操作(如刷新、向前、退后等)信息提供给为渲染引擎;同时,浏览器引擎 为用户界面提供各种如错误提示、资源下载进度等消息。还有,它可以在客户端本地缓存中读写数据。
  • 渲染引擎(Render Engine):渲染引擎负责显示请求的内容。例如,如果请求的内容是HTML文件,则它负责解析文件里的html、css等信息,并将网页内容渲染呈现出来。所以渲染引擎的内部包括了Html解析器、css解析器等。
  • 网络模块(Networking):处理网络请求,比如http请求网页、图片资源等。
  • JavaScript引擎(Js Interpreter ):网页中经常有JS脚本来动态操作网页,就是靠这个JS引擎来解析执行的。比如Chrome浏览器的V8引擎、Safari浏览器的JavaScriptCore引擎。
  • 界面后端(UI Backend):前面介绍的用户界面是展示给用户看到的,界面后端是浏览器的图形库,用来绘制基本的浏览器窗口内控件,如输入框、按钮、单选按钮、组合框和窗口等,不同浏览器绘制的视觉效果不太想同,但功能基本都是一样的。
  • 数据存储(Data Persistence:管理用户数据,将与浏览会话相关联的各种数据存储在硬盘上,例如保存书签、cookie、缓存、偏好设置等各种数据,可通过浏览器引擎提供的API进行调用。

注意:浏览器的内核原先指的指渲染引擎和js引擎,后来由于js引擎越来越独立,现在浏览器的内核代指渲染引擎,但js引擎仍是内核的一部分

渲染引擎(内核)

主流浏览器用的渲染引擎(内核)

  • Firefox :Gecko引擎;
  • IE:Trident引擎;
  • Opera:Presto引擎,后弃用;
  • ChromeSafariOpera: Webkit引擎,13年chrome和opera开始使用Blink引擎;

js引擎

主流浏览器都各用的什么js引擎:

  • IE:老版本IE使用Jscript引擎;IE9之后使用Chakra引擎;
  • Firefox:monkey系列引擎;
  • Safari:SquirrelFish系列引擎;
  • Opera:Carakan引擎;
  • Chrome:V8引擎;(nodeJs其实就是封装了V8引擎)

浏览器是多进程(牺牲空间换时间)

进程是CPU资源分配的最小单位。线程是CPU调度的最小单位,是建立在进程上的一次程序运行单位

打开浏览器的任务管理器,可以看到浏览器的基本进程

浏览器的主要进程

可分为以下几类

  • Browser进程:浏览器的主进程,只有一个,负责界面展示,与用户交互,管理页面,创建和销毁其他进程等
  • GPU进程:用于3D绘制,最多只有一个
  • 第三方插件进程:当使用插件时,主进程就会为其创建一个进程
  • 渲染进程(内核):内部是多线程实现的,下面具体会说说。默认每打开一个Tab页就会创建一个进程,且相互独立互不影响(有个例外:当打开多个空白的Tab页时,浏览器会优化处理,将它们合并为一个进程)。主要负责:页面渲染,脚本执行,事件处理等

为什么采用多进程

多进程的优点:

  • 避免了其它进程的崩溃影响到整个浏览器的运行
  • 多进程充分利用了多核优势
  • 方便使用沙盒模型隔离可疑插件,提高浏览器的稳定性

试想一下,若浏览器是单线程的,当一个Tab页或某一插件崩溃了,就会影响到整个浏览器

浏览器的内核(渲染进程)的多线程

浏览器的内核包含渲染引擎、js引擎和其他模块。

线程分类

可分为下面几部分:

1、GUI渲染线程

  • 也叫渲染内核,负责渲染浏览器界面,解析html、css,构建Dom树和RenderObject树,布局和绘制等
  • 页面需要回流和重绘时,该线程执行

2、JS引擎线程

  • 也称为JS内核,负责处理、解析、运行js代码。
  • 一个Tab页对应一个Render进程,且只有一个JS线程

3、事件触发线程

  • 属于浏览器,用来控制事件循环,当执行到代码块如setTimeOut时(也可来自浏览器内核的其他线程,如鼠标点击、AJAX异步请求等),会将对应任务添加到事件线程中
  • 当对应的事件符合触发条件时,会将事件添加到事件队列的队尾,等待js引擎空闲时处理

4、定时触发线程

  • setIntervalsetTimeout所在的线程,浏览器的定时计数器不在JS引擎中计数的(阻塞影响计数的准确性),所以当计时完毕后将回调函数放到事件队列的尾部,等待JS引擎空闲时执行

5、异步http请求线程

  • http请求时浏览器新开一个线程请求的,当检测到有数据返回时,异步线程就会产生状态变更时间,并将这个事件(失败或成功的回调)放入到事件队列的队尾,等待JS引擎空闲时执行

注意:GUI渲染线程与JS引擎线程互斥,即当JS引擎执行时GUI线程会被挂起,GUI更新时则会被保存到一个队列中等到JS引擎空闲时执行

主进程与内核间的通信

1、Browser进程收到用户请求,首先需要获取页面内容(譬如通过网络下载资源),随后将该任务通过RendererHost接口传递给Render进程

2、Renderer进程的Renderer接口收到消息,简单解释后,交给渲染线程,然后开始渲染

  • 渲染线程接收请求,加载网页并渲染网页,这其中可能需要Browser进程获取资源和需要GPU进程来帮助渲染
  • 当然可能会有JS线程操作DOM(这样可能会造成回流并重绘)
  • 最后Render进程将结果传递给Browser进程

3、Browser进程接收到结果并将结果绘制出来

 总结

这篇文章主要总结了浏览器的组成和浏览器的进程与线程是怎么存在和作用于浏览器中的,还是有很大收获的~~