JavaScript 引擎内部:浏览器如何让你的代码焕发生机

2025-06-10

JavaScript 引擎内部:浏览器如何让你的代码焕发生机

我一直对驱动现代 Web 应用的深层抽象着迷。但随着我逐渐了解 JavaScript 的底层执行机制,我开始对一个更深层次的主题感兴趣——JavaScript 引擎;这些强大的运行时在浏览器中运行时,会悄悄地为 JavaScript 代码注入活力,并为你执行所有这些优化。最近,我一直在研究它们的实现和历史,并想重点介绍一些最有趣的内容。

这篇文章介绍了 JavaScript 引擎如何从解析代码到使其发挥最大性能,引擎构建中使用的常见设计模式(通常可以暗示为什么某些代码比其他代码表现更好),以及我们可以从引擎构建同行那里借鉴的其他一般技巧,以编写更好的 JS。


什么是 JavaScript 引擎?

从高层次上讲,你可以说 JavaScript 引擎是一个程序,它接收你的 JavaScript (JS) 代码并将其转换为计算机可以实际运行的内容。每个浏览器都有自己的 JavaScript 引擎,旨在为用户提供最佳性能:

  • V8:为 Google Chrome 和 Node.js 提供支持。
  • SpiderMonkey:Mozilla Firefox 的引擎。
  • JavaScriptCore:Safari 使用。
  • Chakra:Microsoft Edge 的原始引擎(采用 Chromium 之前)。

这些引擎使您的代码能够运行,并能在各种不同的设备和平台上良好运行。


以下是在浏览器中运行 JavaScript 代码时发生的情况,一步一步:

  • 解析:引擎首先读取(“解析”)你提供的 JavaScript 代码,并将其转换为计算机可以执行的一组指令。然后,这组指令被转换成所谓的“抽象语法树”。

例如:阅读食谱并将其分解为原料和步骤。

  • 编译:现代引擎不会直接从 AST 运行代码,而是将其编译为字节码(较低级别的表示)甚至机器码,以便可以更快地执行。

主要特性:在运行时引擎中,使用即时 (JIT) 编译来优化代码。这意味着它们将调整运行时执行的二进制代码,以使其运行速度更快。

  • 执行:编译完成后,优化后的机器码会在硬件上执行,引擎会持续优化。它会对程序中频繁执行的部分(称为热路径)应用许多高级优化技术,使其运行速度非常快。

JavaScript 引擎中的关键优化

现代引擎使用多种技术来确保 JavaScript 运行速度快且内存高效:

即时 (JIT) 编译

JIT 编译是指引擎在程序执行时会编译一些代码。这意味着引擎对程序的实际运行情况有更深入的了解,因此可以对其进行优化。

示例:如果重复执行循环,引擎会将其识别为热路径并对其进行优化以加快执行速度。

内联缓存

在访问对象属性的过程中,引擎首先检查缓存位置,如果找到,则会减少用于查找属性实际所在位置的总体执行时间。

示例:这基本上意味着如果您多次访问 user.name,引擎将记住存储用户数据的对象,以便下次不必再次找到该对象而可以直接访问它。

垃圾收集

JavaScript 引擎有一个叫做“垃圾收集器”的功能。它本质上是一个程序,当它确定某个对象不再可用或无法访问时,就会释放内存。

示例:如果您在函数中创建了一个对象,并且在该函数完成后,您不再需要它,则引擎会看到该情况并自动将其从内存中删除。


浏览器如何使用 JavaScript 引擎

JavaScript 引擎与浏览器的渲染引擎同时运行。当您访问网站时:

  • 浏览器首先会获取 HTML、CSS 和 JavaScript 文件。
  • 浏览器中的 JavaScript 引擎将解析并执行这些脚本。
  • 渲染引擎将处理过的HTML、CSS、JavaScript组合起来显示网页。

例子:

当您打开任何电子商务网站时,诸如将商品添加到购物车、更新价格、加载产品详细信息等动态功能都由 JavaScript 引擎处理,并且根本不会发生页面刷新。


编写引擎友好型代码的技巧

引擎友好的代码不仅能帮你编写高效的应用程序,还能提升应用程序的可扩展性和可维护性。这里有一个可操作的列表,其中包含一些解释和示例,可以帮助你充分发挥 JavaScript 引擎的潜力。

1. 优化 DOM 操作
频繁且不必要的 DOM 操作会降低应用程序的速度,因为每次更新都会强制浏览器重新计算样式并重新渲染元素。

最佳实践:

通过批量处理来尽量减少直接 DOM 更新。
使用文档片段或像 React 这样的框架来高效处理更新。

例如:而不是:

图片描述

使用文档片段:

图片描述

为什么它有帮助:通过减少 DOM 操作的数量,您可以最大限度地减少回流和重绘,从而使您的应用程序运行得更快。


2. 避免循环和条件中的深度嵌套
引擎难以处理深度嵌套结构,这会使您的代码更难优化和调试。

最佳实践:

将深度嵌套的循环或条件重构为更小的可重用函数。

例如:而不是:

图片描述

使用:

图片描述

为什么有帮助:减少嵌套可以提高可读性并允许引擎更有效地优化代码。


3. 循环中的缓存长度
每次在循环中使用 array.length 时,引擎都会重新计算长度。这可能会导致大型数组的性能问题。

最佳实践:

在循环之前缓存数组长度。

例如:而不是:

图片描述

使用:

图片描述

为什么它有帮助:通过缓存长度,您可以避免冗余计算,从而使循环运行得更快。


4. 使用现代语法和内置方法
与旧技术相比,现代 JavaScript 功能和方法通常会得到引擎的进一步优化。

最佳实践:

  • 使用 let 和 const 代替 var 来声明变量。
  • 在适用的情况下,使用 map、filter 和 reduce 等数组方法代替手动迭代。

例如:而不是:

图片描述

使用:

图片描述

为什么它有帮助:内置方法针对性能进行了高度优化,使您的代码更加简洁、易读。


5. 通过适当的清理避免内存泄漏
当不再需要的对象未被释放时,就会发生内存泄漏,从而导致内存使用量随着时间的推移而增加。

最佳实践:

  • 当不再需要事件监听器时将其删除。
  • 避免不必要地创建全局变量。

例如:而不是:

图片描述

使用:

图片描述

为什么有帮助:适当的清理可确保释放未使用的资源,防止性能随着时间的推移而下降。


6. 对重资产使用延迟加载
仅在需要时加载图像、脚本和数据等资源,以减少应用程序的初始加载时间。

最佳实践:

  • 对图像使用loading="lazy"属性。
  • 在需要时动态导入 JavaScript 模块。

例子:

图片描述

为什么有帮助:延迟加载通过推迟非必要资产的加载来提高性能。


7.避免阻塞主线程
JavaScript 在单个线程上运行,因此长时间运行的操作可能会阻塞 UI 并使您的应用程序无响应。

最佳实践:

对于大量计算,请使用 setTimeout、setInterval 或 Web Workers。

例如:而不是:

图片描述

使用 Web Worker:

图片描述

帮助原因:卸载繁重的任务可防止 UI 冻结,确保流畅的用户体验。


8. 使用内联缓存
JavaScript 引擎通过缓存对象的位置来优化频繁访问的对象属性。确保对象具有一致的结构以获得更好的性能。

最佳实践:

避免动态添加或删除对象的属性。

例如:而不是:

图片描述

使用:

图片描述

为什么它有帮助:引擎优化具有可预测结构的对象,从而加快属性访问。


9. 尽量减少冗余计算,
当结果可以缓存时,避免多次执行相同的计算。

最佳实践:

对于昂贵的函数调用使用记忆法。

例如:而不是:

图片描述

使用:

图片描述

为什么它有帮助:记忆化减少了冗余计算,提高了递归函数的性能。


10. 使用 DevTools 进行分析和优化
使用浏览器的开发人员工具查看代码的哪些部分使其速度变慢。

最佳实践:

-定期分析您的应用程序以查看哪部分代码运行缓慢。-
根据实际使用模式进行优化。

示例:使用 Chrome DevTools 的“性能”选项卡来识别缓慢的脚本或过多的重排并相应地调整代码。

为什么它有帮助:分析将让您获得由数据驱动的洞察力,并让您了解应该将优化重点放在哪个部分。


示例:V8 在 Google Chrome 中的作用

Google 的 V8 引擎是目前最先进的 JavaScript 引擎之一。它为 Chrome 和 Node.js 提供支持,使 Gmail、Google 地图或 YouTube 等现代 Web 应用即使在较慢的机器上也能快速高效地运行。V8 应用了许多性能优化,例如 JIT 编译和内联缓存,以实现这一目标。


JavaScript 引擎的演变

JavaScript 引擎自诞生以来已经走过了漫长的道路!

  • 早期:在早期,引擎直接解释代码,这使得执行速度较慢。
  • JIT 的介绍:后来,引擎开始应用 JIT 编译技术来获得更高的运行时性能。
  • 当前创新:现代引擎利用 WebAssembly(Wasm)集成和多线程执行等先进技术来实现无与伦比的性能。

结论:

作为开发者,我们花费大量时间编写代码,但了解 JavaScript 引擎如何执行这些代码可以帮助我们编写更好、更优化的应用程序。了解 JavaScript 编译器的各种功能(例如 JIT 编译、垃圾回收或内联缓存)后,您就可以利用这些优势来设计解决方案。

希望这篇文章能帮助你理解在浏览器中运行 JavaScript 时屏幕背后的魔力。请继续编写更简洁高效的代码,并感谢这些引擎为使我们的应用程序充满活力所付出的卓越努力。

祝你编程愉快!为构建更快更流畅的网络干杯!

鏂囩珷鏉ユ簮锛�https://dev.to/mukhilpadmanabhan/inside-javascript-engines-how-browsers-bring-your-code-to-life-h1
PREV
所有开发人员必须知道的技巧
NEXT
GO 与 RUST 速度测试 | 2024 年该选哪一个