Maximum call stack exceeded(超出最大调用堆栈)错误是什么意思?

发布时间 2023-05-31 07:05:49作者: 晓风晓浪

你有没有遇到过类似的错误?发生此错误是因为调用堆栈已超出其限制。但是,这是什么意思?

首先,让我们了解什么是调用堆栈。

https://www.java567.com,搜"javascript")

调用堆栈

调用堆栈是 JavaScript 中的一种数据结构,其中包含正在执行的函数。此结构采用后进先出格式。让我们看一个例子:

 function printName() {
   console.log("Dillion")
 }
 
 printName()
 // Dillion

起初,调用堆栈是空的。声明时printName,调用堆栈仍然是空的。待执行时printName(),将其添加到调用栈中:

图片47

当函数完成时,它会从调用堆栈中删除。函数完成发生在:

  • 函数中的所有行都已执行或

  • return在函数中遇到语句

这样,调用堆栈可以跟踪当前正在执行的函数,以及从什么范围执行。

让我们看另一个例子:

 function printName() {
   function printFirstName() {
     console.log("Dillion")
  }
   
   function printLastName() {
     console.log("Megida")
  }
   
   printFirstName()
   printLastName()
   
   console.log("Dillion Megida")
   
 }
 
 printName()
 // "Dillion"
 // "Megida"
 // "Dillion Megida"

在这个例子中,我们声明了一个名为printName. 在这个函数中,我们声明了另外两个函数:printFirstNameprintLastName。两个函数都被调用,然后是 statement console.log("Dillion Megida")

待执行时printName(),将其添加到调用栈中:

图片49

printName(),什么时候printFirstName()要执行,也加入到调用栈中(上图是printName()因为还没有执行完):

图片 53

完成执行后printFirstName()(将“Dillion”记录到控制台),它会从调用堆栈中删除。printLastName()现在要执行,所以它被添加到调用堆栈:

图片51

执行后printLastName()(将“Megida”记录到控制台),它从调用堆栈中删除:

图片52

printName()继续执行,现在执行console.log("Dillion Megida")。您可以在控制台中看到“Dillion Megida”。printName()现在完成,并从调用堆栈中删除:

图片54

这就是调用堆栈如何工作以跟踪当前正在执行的函数。但是调用堆栈有一个最大大小。当您拥有的函数多于调用堆栈中允许的数量时,您会收到超出最大调用堆栈大小的错误。

可以超过最大调用堆栈大小的一种常见情况是递归

我有一个解释这个的视频,你也可以看看。

递归和调用栈

看看这个例子:

 function printNames() {
   console.log("Dillion")
   
   printNames()
   
   console.log("Megida")
 }
 
 printNames()
 // "Dillion" - first call
 // "Dillion" - second call
 // "Dillion" - third call
 // "Dillion" - fourth call
 // "Dillion" - fifth call
 // and so on, until max

在这个例子中,我们声明了printNames. 在这个函数中,我们首先有console.log("Dillion"),然后我们有printNames()

printNames()让我们看看在函数声明之后调用会发生什么。

printNames()--这被添加到调用堆栈:

图片 55

console.log("Dillion")被执行。“Dillion”被记录到控制台。然后printNames()再次执行,将其作为活动函数添加到调用堆栈:

图片56

我们现在在调用堆栈中有两个函数。第一个调用printNames和第二个调用printNames是从第一个调用。

在该函数的第二次调用中,console.log("Dillion")执行将“Dillion”记录到控制台。printNames()然后再次执行该行。第三个调用,作为现在激活的函数被添加到调用栈中:

图片57

现在我们在调用堆栈中有三个函数。由于没有什么能阻止这些函数调用,它会无限地发生,直到“调用堆栈无法再接受它”?:

图片58

调用堆栈具有可同时容纳的函数的最大大小。此大小在不同的浏览器中可能会有所不同。当超过该大小时,您会收到最大调用堆栈大小超出错误。

这也会导致您的 JavaScript 应用程序无响应。而且您绝对不希望您的用户这样做。

在 JavaScript 程序中创建递归时,您还应该有一个基本情况,它会在某些调用后终止递归。这很重要,以免超过调用堆栈大小并导致应用程序崩溃。

这是一个基本案例的示例:

 let counter = 0;
 
 function printNames() {
   console.log("Dillion")
   counter++
   
   if (counter < 5) {
     printNames()
  }
   
   console.log("Megida")
 }
 
 printNames()
 
 // Dillion
 // Dillion
 // Dillion
 // Dillion
 // Dillion
 // Megida
 // Megida
 // Megida
 // Megida
 // Megida

我现在更新了代码以获得一个基本案例。这里的基本情况是“如果计数器变量不再小于 5,则停止递归”。所以当函数被调用时,printNames()被添加到调用栈中。我们有counter0,然后我们将“Dillion”记录到控制台。之后,我们加counter1。然后我们有条件“如果计数器小于 5”。由于counter小于 5,我们执行printNames()

现在调用堆栈有第一次和第二次printNames()调用。

在第五次调用时printNames,调用堆栈将有 5 次调用printNames()

图片59

请记住,前 4 个函数调用尚未完成。在他们完成之前,他们调用了另一个函数,该函数被添加到调用堆栈中。

在这第五次调用中,“Dillion”第五次记录到控制台。counter,在 4,递增 1 到 5。然后检查条件“如果计数器小于 5”。counter(as 5) 不小于 5,所以这是告诉递归停止的基本情况。

由于该函数不再调用自身,因此它继续执行下一行。

然后执行函数中的下一行,即console.log("Megida"). 在这一行之后,调用堆栈中的第五个函数执行完毕,现在离开调用堆栈。

现在第五个函数已经执行完毕,第四个函数可以从它停止的地方继续。第四个函数的下一行是console.log("Megida")在执行时将“Megida”记录到控制台。然后第四个函数离开堆栈:

图片 60

堆栈上的剩余函数将执行完毕,直到堆栈变空:

图片61

图片62

包起来

当您遇到错误“超出最大调用堆栈”时,简单的意思是“调用 sack 现在包含的活动函数超出了它可以包含的数量”。

调用堆栈存储当前正在执行的一个或多个函数。当执行的函数过多时,调用堆栈可能会超出其大小,然后引发错误。这通常发生在没有基本情况的递归情况下。

https://www.java567.com,搜"javascript")