3、调用栈

首先先了解下执行文类型:
全局执行上下文---这是默认或者说基础的上下文,任何不在函数内部的代码都在全局上下文中。它会执行两件事:创建一个全局的window对象(浏览器的情况下),并且设置this的值等于这个全局对象。一个程序中只会有一个全局执行上下文。
函数执行上下文---每当一个函数被调用时,都会为该函数创建一个新的上下文。每个函数都有它自己的执行上下文,不过是在函数被调用时创建的。函数上下文可以有任意多个。每当一个新的执行上下文被创建,它会按定义的顺序执行一系列步骤。
Eval函数执行上下文---执行在eval函数内部的代码也会有它属于自己的执行上下文,但由于Javascript开发者并不经常使用eval,所以在这里我不会讨论它。
执行栈
执行栈,也就是在其它编程语言中所说的”调用栈“, 是一种拥有LIFO(后进先出)数据结构的栈,被用来存储代码运行时创建的所有执行上下文。
当javascript引擎第一次遇到你的脚本时,它会创建一个全局的执行上下文并且压入当前执行栈。每当引擎遇到一个函数调用,它会为该函数创建一个新的执行上下文并压入栈的底部。
引擎会执行那些执行上下文位于栈底的函数。当该函数执行结束时,执行上下文从栈中弹出,控制流程到达当前栈中的下一个上下文。
堆栈溢出
当你达到调用栈最大的大小的时候就会发生这种情况,而且这相当容易发生,特别是在你写递归的时候却没有全方位的测试它。比如下面这段代码
function foo () {
foo()
}
foo()
当我们的引擎开始执行这段代码的时候,它从foo函数开始。然后这个是递归的函数,并且在没有任何终止条件的情况下开始调用自己。因此,每执行一步,就会把这个相同的函数一次又一次地添加到调用堆栈中。

3、调用栈
文章图片
然后,在某一时刻,调用栈中的函数调用的数量超过了调用栈的实际大小,浏览器决定干掉它,抛出一个错误,Uncaught RangeError: Maximum call stack size exceeded.
【3、调用栈】并发与事件循环
调用栈中的函数调用需要大量的时间来处理,那么这会发生什么情况呢?例如,假设你想在浏览器中使用javascript进行一些复杂的图片转码。
事实上,问题是当调用栈有函数要执行,浏览器就不能做任何事,它会被堵塞住。这意味着浏览器不能渲染,不能运行其他的代码,它被卡住了。如果你想在应用里让 UI 很流畅的话,这就会产生问题。
?而且这不是唯一的问题,一旦你的浏览器开始处理调用栈中的众多任务,它可能会停止响应相当长一段时间。大多数浏览器都会这么做,报一个错误,询问你是否想终止 web 页面。

    推荐阅读