JS引擎、运行时与调用堆栈

目录

JavaScript 引擎

内存堆:

调用栈:

运行时

Web API

事件循环:

回调队列:

示例:

调用椎栈


JavaScript 引擎

JavaScript 引擎说起来最流行的当然是谷歌的 V8 引擎了, V8 引擎使用在 Chrome 以及 Node 中

这个引擎主要由两部分组成:

内存堆

这是内存分配发生的地方。当V8引擎遇到变量声明和函数声明的时候,就把它们存储在堆里面。

调用栈

这是你的代码执行时的地方。当引擎遇到像函数调用之类的可执行单元,就会把它们推入调用栈。

JS单线程,指的是在JS引擎中,解析执行JS代码的调用栈是唯一的,所有的JS代码都在这一个调用栈里按照调用顺序执行,不能同时执行多个函数。

运行时

我们可以把JS的运行时环境看作一个大的容器,里面有一些其他的小容器。当JS引擎解析代码时,就是把代码片段分发到不同的容器里。

Web API

(保存一些不在主线程中立即执行的代码片段,有可能在一个分线程中,也有可能在多个分线程中)

还有很多引擎之外的 API,我们把这些称为浏览器提供的 Web API,比如说 事件监听函数DOMHTTP/AJAX请求setTimeout等等。

事件循环

持续的检测调用栈和回调队列,如果检测到调用栈为空,它就会通知回调队列把队列中的第一个回调函数推入执行栈。

回调队列

按照先进先出的顺序存储所有的回调函数。在任意时间,只要Web API容器中的事件达到触发条件,就可以把回调函数添加到回调队列中去。

示例

setTimeout(function(){
    console.log('Hey, Why am I last?')
}, 0)

function sayHi(){
    console.log('Hello')
}

function sayBye(){
    console.log('Goodbye')
}

sayHi()
sayBye()

执行过程是这样的:

  1. JS引擎会检查整段代码的语法错误,如果没有错误,就从头开始深度解析
  2. 首先遇到setTimeout函数调用,把它推入执行栈顶
  3. 解析函数体,发现setTimeout函数是Web API的一种,因此就把它分发到Web API模块然后推出栈
  4. 因为定时器设置了0ms延迟,因此Web API模块立即把它的匿名回调函数推入到回调函数函数队列。事件循环检测执行栈是否是空闲,但是当前栈并不空闲,因为…
  5. 当setTimeout函数一被分发到Web API模块,JS引擎发现了两个函数声明,把它们存储在堆内存里,然后遇到了sayHi函数的调用,就把它推入了栈顶
  6. sayHi函数调用了console.log函数,因此console.log就被推入了栈顶
  7. JS引擎开始解析console.log的函数体,它接收了一个消息去打印‘Hello’,然后被弹出栈
  8. JS引擎返回到函数sayHi的执行,遇到函数的结束符号}之后,把sayHi弹出栈
  9. sayHi函数一出栈,紧接着sayBye函数被调用,它就被推入栈顶,被解析,调用console.log,把console.log推入栈顶,打印一条消息,弹出栈。然后sayBye函数弹出栈
  10. 事件循环检测到执行栈终于空闲了,通知回调队列,然后回调队列把其中的匿名函数推入执行栈
  11. 匿名函数(就是setTimeout的回调函数)被解析,调用console.log,console.log推入栈顶
  12. console.log执行完毕、再出栈
  13. 匿名函数再被推出栈,程序结束

调用椎栈

可以把执行栈认为是一个存储函数调用的栈结构,遵循先进后出的原则。

当开始执行 JS 代码时,首先会执行一个 main 函数,然后执行我们的代码。
根据先进后出的原则,后执行的函数会先弹出栈,在图中我们也可以发现,foo 函数后执行,当执行完毕后就从栈中弹出了。

平时在开发中,也可以在报错中找到执行栈的痕迹

function foo() {
  throw new Error('error')
}
function bar() {
  foo()
}
bar()

可以在上图清晰的看到报错在 foo 函数,foo 函数又是在 bar 函数中调用的。
当我们使用递归的时候,因为栈可存放的函数是有限制的,一旦存放了过多的函数且没有得到释放的话,就会出现栈溢出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值