区分:浏览器、浏览器内核、渲染引擎、Javascript引擎

214 阅读8分钟

在对“JavaScript 是单线程”这个问题进行研究时,不可避免的涉及到“JavaScript 引擎”的研究,然后就产生了对“浏览器内核、渲染引擎、JavaScript 引擎”三者关系的疑惑。

成文借鉴了许多网上文章以及大模型,然后又经过了详细的校读,但由于水平有限,不可避免又有一些认知或语法错误,发现后请留言,我一定改正。如果您有更优秀的观点,也请留言让我学习改进。

浏览器

浏览器是一种软件应用程序,用于检索、呈现和浏览通过互联网传输的信息资源。它主要用于访问和查看在万维网(World Wide Web)上发布的网页,这些网页通常由 HTML 文档构成,可能包含文本、图片、视频和其他多媒体内容。

常用的浏览器软件包括:Chrome、Mozilla FireFox、Safari、Edge等,另外还有在 2022.6.15 彻底关闭的 Internet Explorer,以及其他或简单套壳或阉割或落后的国产浏览器(国产浏览器也有一些优秀的,但我没接触过不讨论)。

浏览器内核

浏览器内核,是浏览器的核心组件,负责解析网页代码(HTML、CSS 和 JavaScript)并将其渲染成用户可以看到和交互的页面。

在有的地方,浏览器内核会直接被称为浏览器的渲染引擎,但这个渲染引擎的定义可能与下文的渲染引擎不同。下文的渲染引擎单指页面的渲染,这里的渲染引擎还包含了 JavaScript 引擎、安全和隐私等关键组件。

渲染引擎(Rendering Engine)

渲染引擎负责解析 HTML 和 CSS 文件,并将它们渲染为用户可以看到的网页。前端开发中的浏览器兼容,指的就是渲染引擎的兼容。常见的渲染引擎包括:

  • Webkit:由苹果公司开发,Safari 浏览器和早期版本的 Chrome 浏览器都用的是 Webkit。
  • Blink:由 Google 基于 Webkit 开发,现在 Chrome(28 开始)、Opera(15 开始,旧版用的是 Presto) 和新版的 Edge(2020.1.15 发布的版本中换成了 Chromium,之前是 EdgeHTML) 都是用 Blink。
  • Gecko:Mozilla Firefox 浏览器使用的渲染引擎。
  • Trident:Internet Explorer 浏览器使用的渲染引擎。

工作过程

渲染引擎的工作过程大致可以分为以下步骤:

1. 解析 HTML

渲染引擎首先解析 HTML 文档,构建一个 DOM(Document Object Model)树。DOM 树是由 HTML 元素组成的节点数,每个节点代表文档中的一个元素。

2. 解析 CSS

接着,渲染引擎解析 CSS 样式表,将 CSS 规则应用到 DOM 树的相应节点上。这一步骤涉及到计算每个节点的最终样式,这个过程称为样式计算。

3. 构建渲染树

渲染引擎将 DOM 树和计算后的样式结合起来,构建一个渲染树(Rendering Tree)。渲染树包含了所有可见的 DOM 元素,以及它们的几何信息(如位置和大小)。

4. 布局(Layout)

渲染树构建完成后,渲染引擎会进行布局(也称为流式布局或重排)。在这个阶段,浏览器会计算每个元素在页面上的具体位置和大小。

5. 绘制(Painting)

布局完成后,渲染引擎会将渲染树中的每个节点绘制到屏幕上,这个过程称为绘制或重绘。绘制过程可能会涉及到文本的排版、图像的渲染、颜色和效果的应用等。

6. 合成(Compositing)

在现代浏览器中,绘制完成后,渲染引擎还会进行合成。合成是将多个页面图层合并成一个最终的图像,然后显示在屏幕上。这个过程可以提高性能,因为它允许浏览器只重绘页面的一部分,而不是整个页面。

7. 响应用户交互

当用户与页面交互(如点击按钮或输入文本)时,渲染引擎会重新执行上述过程的一部分,以反映这些变化。例如,如果用户触发了一个动画,渲染引擎会不断地重绘页面以显示动画效果。

8. 优化和重绘

为了提高性能,渲染引擎会尝试减少重排和重绘的次数。例如,通过使用 CSS 的 transform 和 opacity 属性,可以利用硬件加速来避免重排。

渲染引擎的工作是高度优化的,并且会利用现代计算机的多核处理器和GPU来提高性能。此外,现代浏览器还引入了异步编程模型,允许 JavaScript 代码在不阻塞页面渲染的情况下执行。这些技术共同确保了网页的流畅和快速响应。

JavaScript 引擎(JavaScript Engine)

JavaScript 引擎负责读取、解析、执行 JavaScript 代码,它将 JavaScript 源代码转换为可转化的可执行机器代码,并在运行时管理 JavaScript 程序的执行,通常集成在渲染引擎中。常见的 JavaScript 引擎包括:

  • V8:由 Google 开发,用于 Chrome 浏览器和 Node.js 服务器环境。
  • SpiderMonkey:由 Mozilla 开发,用于 Mozilla Firefox 浏览器。
  • JavaScriptCore:由苹果公司开发,用于 Safari 浏览器。
  • Hermes:由 Meta 开发,是针对 React Native 应用优化的 JavaScript 引擎。

工作过程

JavaScript 引擎的工作过程大致可以分为以下几个阶段:解析、编译、优化和执行:

1. 解析(Parsing)

解析阶段是 JavaScript 引擎收到源代码后的第一个处理步骤。在这个阶段,引擎会进行以下操作:

  • 词法分析(Lexical Analysis):将源代码字符串分解成一个个有意义的代码单元,称为“Token”。Token 是语法分析的输入,例如关键字、标识符、字面量、操作符等。
  • 语法分析(Syntax Analysis):根据 JavaScript 的语法规则,将 Token 转换成一个嵌套的对象,称为“抽象语法树”(Abstract Syntax Tree,AST)。AST 以树状结构表示代码中的元素以及它们之间的关系。

2. 编译(Compilation)

编译阶段涉及将 AST 转换成可以执行的代码。这个过程通常包括:

  • 生成字节码:一些 JavaScript 引擎会将 AST 转换成字节码,这是一种中间状态的代码,可以被进一步转换成机器码。
  • 即时编译(Just-In-Time Compilation,JIT):现代 JavaScript 引擎通常会采用 JIT 技术,将热点代码(频繁执行的代码)编译成高效的机器码,这样可以提高代码的执行速度。

3. 优化(Optimization)

在编译过程中或之后,JavaScript 引擎可能会对代码进行优化,以提高执行效率。优化可能包括:

  • 常量折叠(Constant Folding):在编译时计算常量表达式的值。
  • 死代码消除(Dead Code Elimination):移除不会被执行的代码。
  • 内联缓存(Inline Caching):优化对象属性访问和方法调用的性能。
  • 隐藏类(Hidden Classes):在 JavaScript 这种动态语言中,隐藏类用于优化对象属性的访问。

4. 执行(Execution)

执行过程是 JavaScript 代码实际运行的阶段。在这个阶段:

  • 调用栈(Call Stack):JavaScript 引擎会调用栈来管理函数的调用。每个函数调用都会在调用栈上创建一个栈帧(Stack Frame),包含局部变量和函数参数。
  • 执行字节码或机器码:引擎执行编译后的字节码或机器码,执行过程可能会进行更多的优化。
  • 事件循环(Event Loop):在浏览器环境中,JavaScript 引擎与事件循环紧密协作,处理异步操作,如回调函数的执行。

5. 垃圾回收(Garbage Collection)

虽然不是代码执行的直接部分,但垃圾回收对于 JavaScript 引擎的性能至关重要。垃圾回收器负责识别并清除不再使用的内存,避免内存泄漏。常见的垃圾回收机制包括标记-清除(Mark-and-Sweep)、引用计数(Reference Counting)等。

优化策略

  • 即时编译(JIT Compilation):这是一种动态编译技术,引擎在代码执行时将其编译成机器码。例如,V8 引擎在首次执行代码时可能会以解释方式运行,但当识别出“热点代码”(频繁执行的代码块)时,会将这些代码编译成优化的机器码以提高执行效率。
  • 内联缓存(Inline Caching):这是一种优化属性访问和方法调用的技术。通过缓存先前访问的属性和方法,减少查找时间,从而加快后续访问速度。
  • 隐藏类(Hidden Classes):在 JavaScript 这种动态语言中,对象属性的添加和删除是动态的。隐藏类是一种数据结构,用于跟踪对象的属性状态,从而优化属性访问速度。
  • 内存管理优化:包括有效的垃圾回收策略,如分代垃圾回收,以及优化的对象分配策略,以减少内存分配和回收的开销。
  • 代码分片(Code Splitting):将代码分割成小块,只加载和执行当前需要的部分,可以减少初次加载时间并提高效率。
  • 懒编译(Lazy Compilation):只有在代码实际需要执行时才进行编译,这样可以避免对不会执行的代码进行不必要的编译工作。
  • 去优化(Deoptimization):当监控到代码的某些假设不再成立时,引擎可能会撤销之前的优化措施,以确保代码的正确性。
  • 预测执行(Speculative Execution):基于对代码行为的预测,引擎可能会提前执行某些操作,以提高执行速度。
  • 树摇(Tree Shaking):在构建过程中移除未使用的代码,减少最终打包文件的大小。
  • 死代码消除(Dead Code Elimination):在编译过程中识别并移除不会被执行的代码,减少执行时的负担。