浏览器的工作原理

一、浏览器的主要组件

浏览器的主要组件有以下几种,各大浏览器可能存在细微不同:

浏览器的主要组件

  • 界面控件(User Interface):包括地址栏、前进后退按钮、书签菜单等除了网页显示区域以外的部分;

  • 浏览器引擎(Browser engine):浏览器引擎充当用户界面和渲染引擎之间的中介或桥梁。它根据从用户界面接收到的输入来查询和处理渲染引擎;

  • 渲染引擎(Rendering engine):负责显示请求的内容。例如,如果请求的内容是 HTML,则渲染引擎会解析 HTML 和 CSS,并将解析后的内容显示在屏幕上;

    注意:Chrome等浏览器会运行多个渲染实例:每个选项卡一个。每个选项卡运行在单独的进程中。

    注意:每个浏览器都有自己独特的渲染引擎。不同浏览器版本的渲染引擎也可能不同。下面的列表提到了一些常见浏览器使用的浏览器引擎:

    1. Google Chrome and Opera v15+: Blink
    2. Internet Explorer: Trident
    3. Mozilla Firefox: Gecko
    4. Chrome for iOS and Safari: WebKit
  • 网络(Networking):用于网络请求(如 HTTP 或 FTP)。它包括平台无关的接口和各平台独立的实现;

  • UI后端(UI Backend):绘制基础元件,如组合框与窗口。它提供平台无关的接口,内部使用操作系统的相应实现;

  • JS解释器(JavaScript Interpreter):用于解析和执行JavaScript代码,例如 V8 引擎;

  • 数据存储持久层(Data Persistence):浏览器需要把所有数据存到硬盘上,如cookies。浏览器还支持 localStorage、IndexedDB、WebSQL 和 FileSystem 等存储机制。

二、浏览器中的进程和线程

2.1 进程和线程

进程:进程是操作系统资源分配的基本单位,进程中包含线程。简而言之,就是正在运行的程序。

线程:线程是由进程所管理的。是进程内的一个独立执行的单位,是CPU调度的最小单位。

线程和进程的区别:

  1. 线程是CPU调度的最小单位,而进程是操作系统分配资源的最小单位;
  2. 一个进程由一个或多个线程组成,线程是一个进程中代码的不同执行路线;
  3. 进程之间相互独立,但同一进程下的各个线程之间共享程序的内存空间(包括代码段,数据集,堆等)及一些进程级的资源(如打开文件和信号等),某进程内的线程在其他进程不可见;

线程和进程的区别是什么?- 知乎 https://www.zhihu.com/question/25532384/answer/411179772

2.2 浏览器中的五种进程

Chrome进程架构图

Chrome中 shift + esc 可以查看Chrome的任务管理器

  • 浏览器进程:负责控制浏览器除标签页外的界面,包括地址栏、书签、前进后退按钮等,以及负责与其他进程的协调工作,同时提供存储功能;

  • GPU进程:负责整个浏览器界面的渲染。Chrome刚开始发布的时候是没有GPU进程的,而使用GPU的初衷是为了实现3D CSS效果,只是后面网页、Chrome的UI界面都用GPU来绘制,这使GPU成为浏览器普遍的需求,最后Chrome在多进程架构上也引入了GPU进程;

  • 网络进程:负责页面网络的资源加载,发起和接受网络请求,以前是作为模块运行在浏览器进程里面的,后面才独立出来,成为一个单独的进程;

  • 插件进程:负责插件的运行,因为插件可能崩溃,所以需要通过插件进程来隔离,以保证插件崩溃也不会对浏览器和页面造成影响。出于安全考虑,插件进程都是运行在沙箱模式下的;

    每个扩展程序都是一个插件进程,如果没有启用任意一个扩展程序,那么插件进程的个数就是0。

    所以我们开启一个页面,至少会启动4个进程,分别是:1个浏览器进程、1个GPU进程、1个网络进程和1个渲染进程

    如果后续再打开新的标签页,浏览器进程、GPU进程和网络进程都是共享的,不会再启动。

  • 渲染进程:核心任务是将 HTMLCSSJavaScript 转换为用户可以与之交互的网页,排版引擎 Blink 和 JS解析器 V8引擎 都运行在该进程中,默认情况下,Chrome为每一个Tab标签页创建一个渲染进程。出于安全考虑,渲染进程都是运行在沙箱模式下的。

    默认情况下会为每一个标签页配置一个渲染进程,但是也有例外,比如从A页面里面打开一个新的页面B页面,而A页面和B页面又属于同一站点的话,A和B就共用一个渲染进程,其他情况就为B创建一个新的渲染进程。

浏览器中的进程

我们平时看到的浏览器呈现出页面过程中,大部分工作都是在渲染进程中完成,所以我们来看一下渲染进程中的线程。

2.3 渲染进程中的线程

  • GUI渲染线程:负责渲染页面,解析html和CSS、构建DOM树、CSSOM树、渲染树、和绘制页面,重绘重排也是在该线程执行。在Javascript引擎运行脚本期间,GUI渲染线程都是处于挂起状态的,GUI更新会被保存在一个队列中等到引擎线程空闲时立即被执行
  • JS引擎线程:一个tab页中只有一个JS引擎线程(单线程),负责解析和执行JS,处理页面中用户的交互,以及操作DOM树、CSS样式树。它GUI渲染线程不能同时执行,只能一个一个来,如果JS执行过长就会导致阻塞掉帧GUI渲染线程与JS引擎线程互斥
  • 计时器线程:指 setInterval 和 setTimeout,因为JS引擎是单线程的,所以如果处于阻塞状态,那么计时器就会不准了,所以需要单独的线程来负责计时器工作;
  • 异步HTTP请求线程:XMLHttpRequest连接后浏览器开的一个线程,比如请求有回调函数,异步线程就会将回调函数加入事件队列,等待JS引擎空闲执行;
  • 事件触发线程:主要用来控制事件循环,当一个事件被触发时该线程会把事件添加到待处理队列的队尾,由于JS的单线程关系所有这些事件都得排队等待JS引擎处理。

三、浏览器渲染流程

在浏览器地址栏输入网址并敲下回车的那一刻会发生什么?

  • 对浏览器输入的地址进行 DNS 解析,将域名解析成对应的 IP 地址,如果输入的直接就是 IP 地址,则免去此步骤;
  • 建立 TCP 连接,三次握手;
  • 向这个 IP 地址发送 http 请求,服务器收到这个 http 请求进行处理和响应;
  • 最终浏览器得到服务器响应的内容(一般是一个 html 文件),并将该内容交给渲染引擎处理;
  • 数据传送完毕,断开 TCP 连接,四次挥手。

当浏览器获得一个 html 文件时,会 自上而下 的加载,并在加载过程中进行解析渲染。

浏览器解析渲染页面过程

  • 生成DOM树:获取 HTML 文件并进行解析,生成 DOM (Document Object Model/文档对象模型)树;
  • 执行脚本:遇到 script 标签时,DOM 树构建将暂停,直至脚本加载并执行完毕;
  • 生成CSSOM树:解析 HTML 的同时也会解析 CSS,生成 CSSOM (CSS Object Model)树;
  • 构建渲染树:将 DOM 树和 CSSOM 树结合,生成渲染树(Render Tree);
  • 布局渲染树:根据生成的渲染树,生成布局 (Layout) (这是一次回流),得到节点的几何信息(位置,大小等);
  • 绘制渲染树:根据渲染树以及回流得到的几何信息,进行绘制 (Painting) (这是一次重绘),绘制完毕后进行 Display 展示。

script 标签的 async 和 defer 属性(仅对外链有效,也就是带src属性的script标签):

  • 两者都没有:立即加载并执行脚本,暂停渲染DOM,直至脚本执行完毕。
  • 有 async:加载和渲染后续文档元素的过程将和 script 的加载与执行并行进行(异步)
  • 有 defer:加载后续文档元素的过程将和 script 的加载并行进行(异步),但是 script 的执行要在所有元素解析完成之后

四、V8 引擎

V8引擎

V8 是 Google 的开源高性能 JavaScript 和 WebAssembly 引擎,用 C++ 编写。它用于 Chrome 和 Node.js 等。它实现了 ECMAScript 和 WebAssembly,并运行在 Windows 7 或更高版本、macOS 10.12+ 和使用 x64、IA-32、ARM 或 MIPS 处理器的 Linux 系统上。V8 可以独立运行,也可以嵌入到任何 C++ 应用程序中。

计算机无法识别 JS 代码,需要转换成机器码才能被计算机识别。JS 引擎的作用就是帮助我们将 JS 代码翻译成机器码供 CPU 去执行。

V8 引擎的主要组成部分:

  • Parse 模块:负责将源代码解析成 AST 树(抽象语法树);
  • Ignition 解释器:负责将 AST 树转换成字节码,同时会标记热点代码(HotCode);
  • TurboFan 编译器:负责将热点代码编译成优化后的机器码;
  • Orinoco 垃圾回收器:负责回收不再需要的内存空间。

4.1 Parse 模块

image-20230302134954858

Parse 模块负责将源代码解析成 AST 树,其中有三个重要阶段:词法分析(Scanner)语法分析(Parser)预解析(PreParser)

  • Scanner 扫描器:Scanner 会进行词法分析,将源代码逐词转换成tokens;
  • Parser 解析器:Parser 会进行语法分析,将 tokens 转换成AST树;
  • PreParser 预解析器:PreParser 会将不是立即执行的函数进行预解析,会验证该函数的语法是否正确,解析函数声明以及确定函数作用域。当函数被调用时会将其交给 Parser 进行完全解析。

4.2 Ignition 解释器

Ignition 解释器会将 AST 树编译成字节码(bytecode),开始逐句对字节码解释成机器码并执行。在解释执行的过程中,会标记重复执行的代码为热点代码,将热点代码交给TurboFan处理。

字节码是机器码的抽象,可以看作是小型的构建块。相比机器码,字节码不仅占用内存少,而且生成字节码的时间很快,提升了启动速度。

4.3 TurboFan 编译器

TurboFan 编译器负责将热点代码编译为更高效的机器码储存起来,等到下次执行这段代码的时候,就会用这个机器码直接执行,提升了代码的执行效率。

4.4 Orinoco 垃圾回收器

V8 引擎的垃圾回收器经历过很多变化,当前版本的 GC 叫做 Orinoco。垃圾回收器就负责将不再需要的内存空间释放掉。

在浏览器的发展历史上对于垃圾回收主要有两种 GC 的算法:

  1. 引用计数:当一个对象有一个引用指向它时,那么这个对象的引用就+1,当一个对象的引用为0时,这个对象就可以被销毁掉。引用计数存在一个很大的弊端就是会出现循环引用导致无法消除。目前逐渐被 弃用 了。

    image-20230302144535204

  2. 标记清除:这个算法是设置一个根对象(root object),垃圾回收器会定期从这个根开始,找所有从根开始有被引用到的对象,对于那些没有引用到的对象,就认为是不可用的对象,随后便会销毁掉。目前JS引擎采用较广泛的就是标记清除法。当然 V8 引擎也对该算法进行了进一步的优化。

    image-20230302144903649

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值