为网络编写代码有时感觉有点神奇,因为我们在文件中编写字符序列,在浏览器中打开该文件,然后观看它的实现。但了解魔法背后的技术可以帮助你更好地磨练你作为程序员的手艺。
在本文中,您将通过掌握支持浏览器的 JavaScript 引擎的复杂性,了解 JavaScript 驱动的 Web 或移动堆栈幕后发生的事情。让我们来分析一下 JavaScript 引擎的作用,为什么不同的平台使用不同的引擎,它们多年来是如何发展的,以及为什么我们作为开发者应该关心。
“JavaScript 引擎”通常被称为虚拟机的一种。 “虚拟机”是指给定计算机系统的软件驱动模拟。虚拟机有很多种类型,它们根据模拟或替代实际物理机的精确程度进行分类。
例如,“系统虚拟机”提供了可以执行操作系统的平台的完整模拟。 Mac 用户可能熟悉 Parallels,这是一个系统虚拟机,可让您在 Mac 上运行 Windows。
另一方面,“进程虚拟机”的功能不太齐全,只能运行一个程序或进程。 Wine 是一个进程虚拟机,允许您在 Linux 机器上运行 Windows 应用程序,但不会在 Linux 机器上提供完整的 Windows 操作系统。
JavaScript 引擎是一种专门用于解释和执行 JavaScript 代码的进程虚拟机。
注意:区分通过布局网页来驱动浏览器的引擎与解释和执行代码的低级 JavaScript 引擎非常重要。这篇关于浏览器如何工作的文章提供了很好的解释。
那么 JavaScript 引擎到底是什么?它有什么作用?
总而言之,JavaScript 引擎的基本工作是获取开发人员编写的 JavaScript 代码,并将其转换为可以由浏览器解释甚至嵌入到应用程序中的快速、优化的代码。事实上,JavaScriptCore 称自己为“优化虚拟机”。
更准确地说,每个 JavaScript 引擎都实现一个 ECMAScript 版本,JavaScript 是其中的一种方言。随着 ECMAScript 的发展,JavaScript 引擎也在不断发展。之所以有这么多不同的引擎,是因为每个引擎都设计用于不同的 Web 浏览器、无头浏览器或 Node.js 等运行时。
您可能熟悉网络浏览器,但什么是无头浏览器?它是一个没有图形用户界面的网络浏览器。它们对于针对您的网络产品运行自动化测试非常有用。从 Chrome 版本 59 和 Firefox 版本 56 开始,常规浏览器可以以这种方式使用,特别是用于测试。 Node.js 在哪里适合这个? Node.js 是一个异步、事件驱动的框架,允许您在服务器端使用 JavaScript。由于它们是 JavaScript 驱动的工具,因此它们由 JavaScript 引擎提供支持。
考虑到上面虚拟机的定义,将 JavaScript 引擎称为进程虚拟机是有意义的,因为它的唯一目的是读取和编译 JavaScript 代码。这并不意味着它是一个简单的引擎。例如,JavaScriptCore 有六个“构建块”,用于分析、解释、优化和垃圾收集 JavaScript 代码。
这取决于引擎。让我们考虑两个重要的引擎:WebKit 的 JavaScriptCore 和 Google 的 V8 引擎。这两个引擎处理代码的方式不同。
JavaScriptCore 执行一系列步骤来解释和优化脚本:
它执行词法分析,将源代码分解为一系列标记或具有已识别含义的字符串。
然后解析器会分析标记的语法并构建到语法树中。
然后启动四个 JIT(即时)进程,分析并执行解析器生成的字节码。
简单来说,这个 JavaScript 引擎获取您的源代码,将其分解为字符串(也称为词法分析),获取这些字符串并将它们转换为编译器可以理解的字节码,然后执行它。
Google 的 V8 引擎用 C 语言编写,还编译和执行 JavaScript 源代码、处理内存分配以及垃圾收集剩余部分。它的设计由一个编译器管道组成,可将源代码直接编译为机器代码:
Ignition,生成字节码的解释器
TurboFan,一种优化编译器,可将字节码编译为机器代码
SparkPlug,一个补充 TurboFan 的编译器
如果您对历史感兴趣,这个新管道取代了 V8 之前使用的较旧的 Full-codegen 和 Crankshaft 双编译器设计。
编译过程生成机器代码后,引擎会将 ECMA 标准中指定的所有数据类型、运算符、对象和函数公开给浏览器或任何需要使用它们的运行时,例如 Node.js, Deno 或 Electron(由 Visual Studio Code 使用)。
如果 JavaScript 引擎在后台悄悄运行,解析代码并将其分解为可读字符串,以便编译器可以读取和编译它,那么运行时往往会吸引更多关注。这是为什么?
众所周知的运行时在 JavaScript 引擎之上工作,扩展了它们的功能。最知名的是 Node,但 Deno 和 Bun 是这个领域的新人。 Node 和 Deno 嵌入了 V8,Bun 嵌入了 JavaScriptCore。
Bun 声称比 Node 或 Deno 运行得更快,因为 JavaScriptCore 比 V8 更快,每秒处理 69,845 个 http 请求,而 Node 为 16,288 个,Deno 为 12,926 个。
正如 Bun 的文档所述,这些运行时的目标是“在浏览器之外运行世界上大部分 JavaScript,为未来的基础设施带来性能和复杂性增强,并通过更好、更简单的工具提高开发人员的生产力。”事实上,这些运行时利用 JavaScript 引擎的强大功能使 JavaScript 在浏览器之外运行。
NativeScript 是专门为使用 JavaScript 构建的跨平台本机移动应用程序开发而构建的运行时的一个很好的示例。
这些运行时也是为了解决 JavaScript 单线程架构带来的一些固有问题而构建的。例如,Node 优先考虑例程的异步、无线程执行。所有这些运行时都提供了精心策划的开发人员体验,包括对深受喜爱的 API(如 fetch、websocket,甚至是 React 开发人员喜爱的 JSX)的内置支持。这可能是它们容易吸引开发者关注的原因。
总体而言,运行时解决了标准浏览器架构及其驱动引擎的性能差距。随着引擎的发展,这些运行时肯定也会发展。
有多种 JavaScript 引擎可用于分析、解析和执行客户端代码。随着每个浏览器版本的发布,JavaScript 引擎可能会发生更改或优化,以跟上 JavaScript 代码执行的最新技术水平。
在被这些引擎的名称完全混淆之前,请记住,大量的营销活动都投入到了这些引擎及其背后的浏览器中,这是很有用的。在这篇对 JavaScript 编译的有用分析中,作者讽刺地指出:“如果你不知道,编译器大约 37% 是由营销组成的,而品牌重塑是你可以对编译器做的为数不多的事情之一,从营销角度来看,因此列车名称为:SquirrelFish、Nitro、SFX...”
在牢记命名和重命名这些引擎的起起落落的同时,注意 JavaScript 引擎历史上的一些重大事件也是很有用的。我为您整理了一个方便的图表:
Browser, Headless Browser, or Runtime | JavaScript Engine |
---|---|
Mozilla | Spidermonkey |
Chrome | V8 |
IE | Chakra |
Safari | JavaScriptCore* |
Node.js | V8 |
Deno | V8 |
Bun | JavaScriptCore |
Edge** | Blink and V8 |
*JavaScriptCore 被重写为 SquirrelFish,更名为 SquirrelFish Extreme,也称为 Nitro。然而,将 JavaScriptCore 称为 WebKit 实现(例如 Safari)底层的 JavaScript 引擎仍然是正确的说法。
**Edge 最初使用 Chakra 引擎,其中部分引擎被微软开源。然后,Edge 被重建为 Chromium 浏览器,底层带有 Blink 和 V8 JavaScript 引擎。
JavaScript 引擎的代码解析和执行过程的目标是在最短的时间内生成最优化的代码。
最重要的是,这些引擎的发展与我们对发展网络和移动环境以使其尽可能高性能的追求是并行的。要跟踪这一演变,您可以在基准测试图表中查看各种引擎的表现,例如 arewefastyet.com 上生成的图表。
任何 Web 开发人员都需要了解浏览器中固有的差异,这些浏览器显示我们努力生成、调试和维护的代码。为什么某些脚本在一种浏览器上运行缓慢,但在另一种浏览器上运行速度更快?
类似地,移动开发人员,尤其是那些使用 webview 来显示其内容编写混合移动应用程序的开发人员,会想知道哪些引擎正在解释他们的 JavaScript 代码。所有关心用户体验的 Web 开发人员都应该了解小型设备上各种浏览器固有的限制和提供的可能性。跟上
的变化
随着您成为 Web、移动或应用程序开发人员,JavaScript 引擎将是值得花时间的。
本文最初于 2015 年出现在 Telerik 开发者网络上,此后已针对 2022 年及以后进行了修订和更新。维基百科的 JavaScript 引擎条目中引用了原始文章。
以上是什么是 JavaScript 引擎?的详细内容。更多信息请关注PHP中文网其他相关文章!