精通 JavaScript 🧑💻:js 引擎的工作原理
📘 引言
🔎 发动机有多少种类型?
⚙️ JS引擎的工作原理
🌐 资源
大家好👋,希望你们一切都好。
我计划通过这篇文章开启一个名为“精通 JavaScript”的新版块,在这里我将详细阐述我随着时间推移所学到的这门编程语言的知识,希望你们觉得这些内容有用。
那么,让我们开始吧!
📘 引言
JavaScript 是一种解释型编程语言,它诞生于客户端。
- 解释型语言是指程序员编写的代码由解释器逐行“读取”,同时将其转换为 CPU 可以理解的二进制代码,以便执行。
- 之所以称之为客户端程序,是因为它运行的环境是浏览器,而浏览器位于智能手机、电脑等客户端设备上。
(自 2009 年以来,由于 Node.js 的出现,JavaScript 也开始在服务器端运行,但我会在以后的文章中讨论这一点,这里我想重点关注浏览器端。)
因此,负责管理 js 执行生命周期的元素是位于浏览器内部的JavaScript 引擎。
🔎 发动机有多少种类型?
如今,各种浏览器都采用了多种不同的渲染引擎,它们之间有很多共同的功能。最早的引擎之一是1995年为Netscape浏览器开发的SpiderMonkey,目前Mozilla Firefox也在使用;Chrome浏览器使用V8引擎,它是目前最强大的引擎之一;Safari浏览器使用Nitro引擎,等等。
⚙️ JS引擎的工作原理
现在我们知道了浏览器引擎是什么,接下来我们可以更具体地了解它是如何工作的。
JS运行时环境
运行时环境由调用栈和内存堆组成:
- 调用栈是一种数据结构,用于存储待执行的指令,并在指令执行完毕后将其移除。首先添加到调用栈的是全局执行上下文(GEC)。GEC 由全局对象构成,该对象包含程序员编写的所有 JavaScript 内置函数和全局变量(例如,对于浏览器而言,它是Window对象)。之后,开发者创建的函数会将其他元素添加到调用栈中。因此,当代码执行完毕后,从调用栈中移除的最后一个元素就是 GEC。
- 另一方面,在内存堆中,变量是动态存储的:变量在函数调用时自动分配,并在函数退出时自动“删除”。这是由垃圾回收器完成的。
以下是一个例子:
function one() {
return 1
}
function two() {
return one() + 1
}
function three() {
return two() + 1
}
console.log(three())
其中main()是 GEC。
我们知道,JavaScript 允许通过Web API中包含的特殊功能异步执行。 实际上,异步函数正是在这些 Web API 中执行的,而不是在调用栈中执行的(因为我们只有一个调用栈)。
之后,API 的返回结果(即其中的函数)会被放入回调队列,等待调用栈清空。
引擎能够检测到调用栈为空,因此需要将数据从回调队列中移出,这要归功于事件循环,它本质上是一个持续监控调用栈的监听器。
举个例子:
console.log("start")
setTimeout(function() {
console.log("1 sec delay")
}, 1000)
console.log("end")
JIT编译器
正如我之前所说,JavaScript 是一种解释型语言。
但如今像 V8 这样的浏览器已经实现了即时编译器(JIT) ,也就是说,它们结合了解释器和编译器的特性,以实现更好的性能。
解释器分析源代码所需时间很短,但代码执行过程中可能会出现速度下降的情况(因为它每次调用方法时都会解释字节码,这在例如存在循环的情况下并非最佳选择)。
另一方面,编译器会扫描整个程序并将其一次性全部翻译成机器代码,从而实现更高的稳定性,但整体执行速度要慢得多。
JIT 编译器通过解释代码来优化时间,并将可重用的部分(例如方法)“及时”编译成本地机器语言以运行,从而将代码分配给编译器。
🌐 资源
JavaScript 引擎、调用栈、回调队列、Web API 和事件循环
(我从上面的链接中获取了 GIF 和示例)
感谢阅读🙂!希望您喜欢这篇文章,也希望它对您有所帮助。如果觉得有用,请点个赞。
您可以关注我,以便及时了解我的最新文章。




