揭秘JavaScript引擎:浏览器如何让你的代码活起来
我一直对现代 web 应用背后的深刻抽象概念感到着迷。但是,随着我对 JavaScript 在底层的执行方式有了更多的了解,我对一个更深的话题产生了兴趣——JavaScript 引擎;这些强大的运行时默默地赋予你的 JavaScript 代码生命,在浏览器中运行时,它们还会为你进行所有优化。最近,我一直在研究它们的实现和历史,想分享其中一些最有趣的事实。
这篇帖子介绍了JavaScript引擎如何从解析你的代码到使其运行得更快更高效的过程,构建引擎时常使用的设计模式(这些模式也可以解释为什么某些代码比其他代码快),以及其他一些可以从引擎构建者那里借鉴的建议,来编写更高效的JS代码。
此处省略
此处省略
此处省略
什么是JavaScript引擎?
简单来说,JavaScript引擎就是一个程序,它将你的JavaScript代码转换成计算机可以运行的形式。每个浏览器都有自己的JavaScript引擎,旨在为用户提供最佳体验。
- V8 :驱动着 Google Chrome 和 Node.js。
- SpiderMonkey :Mozilla Firefox 的引擎。
- JavaScriptCore :驱动着 Safari。
- Chakra :微软 Edge 引擎(在采用 Chromium 之前所使用的)。
这些引擎是使你的代码在各种设备和平台上高效运行的关键。
……
当你在浏览器中运行JavaScript代码时,这里就是每一步会发生的情况。
- 分析:引擎首先读取(分析)你给它的 JavaScript 代码,并将其转换为计算机可以理解的一系列指令。然后被转换为一种称为“抽象语法树”的数据结构。
例如:读一个食谱,并将它拆分成材料和步骤。
- 编译过程:现代引擎不会直接从AST运行代码,而是将代码编译成字节码,甚至直接编译成机器代码,这样就可以更快地执行。
关键特性:即时(JIT)编译。在运行过程中,引擎使用即时(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 的特性和内置方法
现代 JavaScript 的特性和内置方法通常比旧技术更被引擎优化,因此更适合使用。
最佳做法:
- 请尽量使用
let
和const
而不是var
来声明变量。 - 当适用时,尽量使用数组方法(如
map
、filter
和reduce
),而不是手动迭代。
例如:而不是
用法:
为什么这有用:内置方法高效,让代码更简洁易读。
5. 避免内存泄漏,做好释放工作
内存泄漏发生于不再需要的对象未被释放时,导致内存占用随时间不断增加。
最佳做法:
- 不应及时在不再需要时才移除事件监听器。
- 避免不必要的全局变量。
例如:而是:
这是一张图片:
用法:
为什么这有帮助:正确的清理确保释放未使用的资源,防止性能随时间逐渐下降。
6. 使用按需加载处理大文件资源
仅在需要时加载这些资源,以减少应用的启动时间。
最佳做法:
- 为图片使用
loading="lazy"
属性(例如:<img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="image.jpg" loading="lazy">
)。 - 请按需动态加载 JS 模块。
比如:
为什么有帮助的是:延迟加载通过延迟加载非必需资源来提升性能。
7. 避免阻塞主进程
JavaScript 运行在一个单独的线程上,所以长时间运行的任务会阻塞 UI,从而使您的应用无法响应。
最佳做法:
可以使用 setTimeout
、setInterval
或 Web Workers
来处理那些消耗大量资源的计算任务。
例如:改为:
如需查看图片,请点击此处
使用 Web Worker 来:
这是一张图片,你可以在这里查看它:
为什么这有帮助:将繁重的任务转移给后台处理可以防止用户界面冻结,确保用户界面操作流畅。
8. 启用内联缓存
JavaScript 引擎通过缓存经常访问的对象属性的位置来优化性能。确保对象的结构保持一致,以获得更好的性能。
最佳做法
尽量不要在对象上动态添加或删除属性。
例如:改为:
用途。
为什么有帮助的是:引擎优化具有可预测结构的对象,从而使属性访问速度加快。
9. 减少冗余计算
避免重复执行相同的计算,尤其是在结果可以被缓存时。
最佳做法:
使用记忆化来减少耗时函数的调用。
例如:而不是:
改为:
例如:而是:
用法:
为什么有帮助的是:缓存减少了重复计算,提高了递归函数的执行效率。
10. 使用 DevTools 查看并优化代码的性能
使用浏览器的开发者工具来找出并优化拖慢运行速度的代码部分。
最佳做法:
-定期分析应用,找出运行缓慢的部分。
-找出哪些代码运行得慢。
-根据实际使用模式来优化。
示例:使用 Chrome DevTools 的 Performance 标签找到慢脚本或过多重绘,然后根据需要调整你的代码。
有帮助的原因是:剖析会从数据中为你提供见解,并让你知道该在哪部分下功夫优化。
V8 在 Google Chrome 中的角色
Google的V8引擎是目前最先进的JavaScript引擎之一。它驱动着Chrome和Node.js,使得像Gmail、Google Maps和YouTube这样的现代网页应用即使在较慢的机器上也能快速高效地运行。V8通过诸如即时编译和内联缓存等性能优化技术来实现这一目标。
JavaScript 引擎的演进历程
从最初到现在,JavaScript 引擎的发展真是进步了很多!
- 早些时候:引擎只是直接解释代码,这导致执行速度变慢。
- JIT 的引入:后来,引擎开始采用 JIT 编译技术,从而提高了运行时性能。
-
现在的创新:现代引擎采用了诸如 WebAssembly (Wasm) 集成和多线程执行等高级技术,从而实现了卓越的性能。
-
- *
最后:
作为开发者,我们花了很多时间编写代码。了解JavaScript引擎是如何执行代码的可以帮助我们编写更好、更优化的应用。当你了解JavaScript引擎具备的能力,比如即时编译、垃圾回收和内联缓存,你就能利用这些优势来设计你的解决方案。
我希望这篇帖子能帮助你理解每当你在浏览器中运行JavaScript时背后的魔法。继续写出更干净、更高效的代码,并认识到JavaScript引擎为让我们的程序更生动所作出的巨大努力。
编程愉快!!! 干杯,祝我们构建更快速更流畅的网页 😊
共同学习,写下你的评论
评论加载中...
作者其他优质文章