ChatGPT解决这个技术问题 Extra ChatGPT

超出最大调用堆栈大小错误

我正在使用 Direct Web Remoting (DWR) JavaScript 库文件,并且仅在 Safari(桌面和 iPad)中出现错误

它说

超出最大调用堆栈大小。

这个错误到底是什么意思,它是否完全停止处理?

还有对 Safari 浏览器的任何修复(实际上在 iPad Safari 上,它说

JS:执行超时

我假设是相同的调用堆栈问题)

尝试通过 ajax 中的 data 发送变量(未声明它们)时出现此错误。通过声明变量修复了错误。
无限循环 ...
对我来说,我的 JavaScript 函数的名称是 onclick(),我得到了这个错误 :-) 虽然这些是保留名称

C
Community

这意味着在您的代码中的某处,您正在调用一个函数,该函数又调用另一个函数,依此类推,直到您达到调用堆栈限制。

这几乎总是因为具有未满足基本情况的递归函数。

查看堆栈

考虑这段代码...

(function a() {
    a();
})();

这是几次调用后的堆栈...

https://i.stack.imgur.com/aSwnu.png

如您所见,调用堆栈会不断增长,直到达到限制:浏览器硬编码堆栈大小或内存耗尽。

为了修复它,请确保您的递归函数具有能够满足的基本情况......

(function a(x) {
    // The following condition 
    // is the base case.
    if ( ! x) {
        return;
    }
    a(--x);
})(10);

非常感谢..所以有什么方法/工具可以让我用尽堆栈限制..再次,因为这是一个巨大的库文件,不是我创建的,我不完全知道在哪里事情可能会出错..
@Oliver 如果你必须运行一个函数近 300 万亿次,你可能做错了什么。
@Oliver-您可能想研究动态编程-我的猜测是您没有那么多独特的解决方案,您正在重复步骤,因此您可能需要将其编程为多项式时间而不是二次。 en.wikipedia.org/wiki/Dynamic_programming
@Akhoy 在常规函数中是的,但请考虑递归函数。它调用另一个(自身)并将前者的返回地址留在堆栈上(否则 PC 会知道去哪里?)这当然会再次调用自身,每次将返回地址压入堆栈。当由于下个世纪不太可能遇到的基本情况而导致这种情况消失时,您会遇到堆栈溢出。
您的代码运行相同的低效段 134217728 次。不开玩笑,它很慢。您应该使用按位运算符,这样您就可以将 9 级循环展开为一级循环。
d
double-beep

如果您不小心两次导入/嵌入相同的 JavaScript 文件,有时会得到此信息,值得在检查器的资源选项卡中检查。


当您不小心两次导入/嵌入相同的 JS 文件时,通常会发生此问题。我不想推测导致递归循环的确切过程,但我认为这就像以 100 英里/小时的速度驾驶两辆相同的汽车通过同一个收费站。
我认为情况并非如此。如果嵌入了两个相同类型的函数或变量,后者将覆盖之前的定义。
是的...我真的不知道它为什么会发生或过程是什么,尽管它也会覆盖。
派对有点晚了,但可以想象,当代码在任何函数之外时,两者都将在两个 JS 文件中执行,并且一个可能不会相互覆盖,因为它们在任何函数之外。
@lucygenik 下次您在批准对您的帖子进行巨魔编辑时要更加小心。这篇文章几乎被作为垃圾邮件删除(查看历史记录)
F
FK-

就我而言,我发送的是输入元素而不是它们的值:

$.post( '',{ registerName: $('#registerName') } )

代替:

$.post( '',{ registerName: $('#registerName').val() } )

这将我的 Chrome 选项卡冻结到一个点,当页面变得无响应时,它甚至没有向我显示“等待/终止”对话框......


我想知道为什么这样的错误没有例外......谢谢!
非常感谢,这救了我
我正要添加这个作为可能的解决方案。我只是做了这件事哈哈
“我想知道为什么这种错误没有例外......”因为它是javascript。
谢谢你。这是问题
A
Aaron Digulla

在您的代码中某处存在递归循环(即最终一次又一次地调用自身直到堆栈已满的函数)。

其他浏览器要么有更大的堆栈(所以你会得到一个超时),要么他们出于某种原因吞下了错误(可能是一个错误的 try-catch)。

发生错误时使用调试器检查调用堆栈。


非常感谢您的回复。在 IE/FF 上,代码似乎运行良好..仅在桌面 Safari 和 iPad Safari 中,我得到了错误。实际上,JS 文件不是我自己创建的,而是一个库文件(来自 DWR engine.js)。directwebremoting.org 另外,当您说“调试器检查调用堆栈”时,我该如何使用 Safari Inspector 来做到这一点?
我没有使用 Safari Inspector 的经验。尝试打开 JavaScript 调试器并加载您的页面。当抛出未捕获的错误时,调试器应该停止。如果这不起作用,请询问超级用户或网站管理员(见页面底部)
有 2 个函数名称相同!!哦!
S
Simon_Weaver

检测堆栈溢出的问题是有时堆栈跟踪会展开,您将无法看到实际发生的情况。

我发现 Chrome 的一些较新的调试工具对此很有用。

点击 Performance tab,确保 Javascript samples 已启用,您会得到类似的结果。

溢出在哪里很明显!如果您点击 extendObject,您将能够实际看到代码中的确切行号。

https://i.stack.imgur.com/qtrDa.png

您还可以查看可能有用或可能没有帮助的时间安排或红鲱鱼。

https://i.stack.imgur.com/sGnvq.png

如果您实际上找不到问题,另一个有用的技巧是在您认为问题所在的地方放置大量 console.log 语句。上面的上一步可以帮助您解决此问题。

在 Chrome 中,如果您重复输出相同的数据,它会像这样显示问题更清楚的地方。在这种情况下,堆栈在最终崩溃之前达到了 7152 帧:

https://i.stack.imgur.com/8wVYn.png


对于任何阅读此答案的人。当然它对我有用,我能够将其缩小为递归函数调用。我可以使用“性能”选项卡轻松地立即跟踪问题。这是由于 2 个角度元素资产包含在一个单独的应用程序中。一旦我禁用了其中一个元素,问题就消失了。希望这对某人有帮助!
N
Nate Glenn

就我而言,我使用以下命令将大字节数组转换为字符串:

String.fromCharCode.apply(null, new Uint16Array(bytes))

bytes 包含数百万个条目,太大而无法放入堆栈。


同一行我也有同样的问题!!谢谢
那么转换大字节数组的最佳解决方案是什么?
@KarthikHande 您必须在 for 循环中而不是一次调用中完成。 var uintArray = new Uint16Array(bytes); var converted = []; uintArray.forEach(function(byte) {converted.push(String.fromCharCode(byte))});
如何将其转换为 JSON?我尝试了 JSON.parse 但它没有用...我正在使用 Uintl8Array
@KarthikHande 如果没有看到整个问题,我无法判断。请打开另一个包含所有详细信息的问题。
V
Vim Diesel

就我而言,单击事件正在子元素上传播。所以,我不得不把以下内容:

e.stopPropagation()

点击事件:

 $(document).on("click", ".remove-discount-button", function (e) {
           e.stopPropagation();
           //some code
        });
 $(document).on("click", ".current-code", function () {
     $('.remove-discount-button').trigger("click");
 });

这是html代码:

 <div class="current-code">                                      
      <input type="submit" name="removediscountcouponcode" value="
title="Remove" class="remove-discount-button">
   </div>

b
bendytree

这也可能导致 Maximum call stack size exceeded 错误:

var items = [];
[].push.apply(items, new Array(1000000)); //Bad

同样在这里:

items.push(...new Array(1000000)); //Bad

Mozilla Docs

但请注意:以这种方式使用 apply 时,可能会超出 JavaScript 引擎的参数长度限制。应用带有太多参数的函数(考虑超过数万个参数)的后果因引擎而异(JavaScriptCore 的硬编码参数限制为 65536),因为限制(实际上甚至是任何过大堆栈的性质行为)未指定。有些引擎会抛出异常。更有害的是,其他人会任意限制实际传递给应用函数的参数数量。为了说明后一种情况:如果这样的引擎有四个参数的限制(实际限制当然要高得多),就好像参数 5、6、2、3 已被传递以应用于上面的示例,而不是整个数组。

所以试试:

var items = [];
var newItems = new Array(1000000);
for(var i = 0; i < newItems.length; i++){
  items.push(newItems[i]);
}

在将节点插入 dom 时,这是非常糟糕的做法,但是您可能是对的……如果您有足够的节点,在循环之后执行 el.append(...divs) 会导致此错误。
c
chim

检查 Chrome 开发工具栏控制台中的错误详细信息,这将为您提供调用堆栈中的函数,并引导您找到导致错误的递归。


N
Nandostyle

就我而言,这是我有 2 个同名的变量!


D
Dr. Dama

如果您出于某种原因需要运行无限进程/递归,您可以在单独的线程中使用 webworker。 http://www.html5rocks.com/en/tutorials/workers/basics/

如果要操作 dom 元素并重绘,请使用动画 http://creativejs.com/resources/requestanimationframe/


h
hayesgm

这里几乎每个答案都表明这只能由无限循环引起。这不是真的,否则您可能会通过深度嵌套调用超出堆栈运行(并不是说这很有效,但它肯定在可能的范围内)。如果您可以控制 JavaScript VM,则可以调整堆栈大小。例如:

node --stack-size=2000

另请参阅:How can I increase the maximum call stack size in Node.js


S
Scott

我们最近在我们正在处理的管理站点中添加了一个字段 - contact_type... 简单吧?好吧,如果你调用选择“类型”并尝试通过 jquery ajax 调用发送它,它会失败,这个错误深埋在 jquery.js 中 不要这样做:

$.ajax({
    dataType: "json",
    type: "POST",
    url: "/some_function.php",
    data: { contact_uid:contact_uid, type:type }
});

问题是 type:type - 我相信是我们将参数命名为“type” - 有一个名为 type 的值变量不是问题。我们将其更改为:

$.ajax({
    dataType: "json",
    type: "POST",
    url: "/some_function.php",
    data: { contact_uid:contact_uid, contact_type:type }
});

并相应地重写了 some_function.php - 问题解决了。


感谢您写下这个答案。实际上,我发现我没有创建要发布到服务器端脚本的变量。
A
Aman

就我而言,我基本上忘记了获得 inputvalue

错误的

let name=document.getElementById('name');
param={"name":name}

正确的

let name=document.getElementById('name').value;
param={"name":name}

它类似于 @FKasa ,这是在 javascript 中
正是发生在我身上的事情——我不小心发送了整个输入字段,而不仅仅是字段的值。
E
El_boogy

发送输入元素而不是它们的值很可能会像 FK 提到的那样解决它


B
Baz Guvenkaya

在我的例子中,两个 jQuery 模态显示堆叠在一起。防止这解决了我的问题。


o
onmyway133

检查您是否有一个调用自身的函数。例如

export default class DateUtils {
  static now = (): Date => {
    return DateUtils.now()
  }
}

R
ReemRashwan

对于我作为 TypeScript 的初学者来说,这是 _var1 的 getter 和 setter 的问题。

class Point2{
    
    constructor(private _var1?: number, private y?: number){}

    set var1(num: number){
        this._var1 = num  // problem was here, it was this.var1 = num
    }
    get var1(){
        return this._var1 // this was return this.var1
    }
}

K
Kihats
dtTable.dataTable({
    sDom: "<'row'<'col-sm-6'l><'col-sm-6'f>r>t<'row'<'col-sm-6'i><'col-sm-6'p>>",
    "processing": true,
    "serverSide": true,
    "order": [[6, "desc"]],
    "columnDefs": [
        {className: "text-right", "targets": [2, 3, 4, 5]}
    ],
    "ajax": {
        "url": "/dt",
        "data": function (d) {
            d.loanRef = loanRef;
        }
    },
    "fnRowCallback": function (nRow, aData, iDisplayIndex, iDisplayIndexFull) {
        var editButton = '';
        // The number of columns to display in the datatable
        var cols = 8;
        // Th row element's ID
        var id = aData[(cols - 1)];
    }
});

在上面的 data 函数中,我使用了相同的名称 d.loanRef = loanRef 但没有创建变量 loanRef 因此递归地声明自己。

解决方案:声明一个 loanRef 变量,或者更好的是,使用与 d.loanRef 上使用的名称不同的名称。


E
Elijah Lynn

如果在我的计算机上的 Chrome 32 中减 1,则以下相同代码的两个调用都可以工作,例如 17905 与 17904。如果按原样运行,它们将产生错误“RangeError:超出最大调用堆栈大小”。这个限制似乎不是硬编码的,而是取决于您机器的硬件。看起来,如果作为函数调用,这个自我强加的限制比作为方法调用的要高,也就是说,当作为函数调用时,这个特定的代码使用更少的内存。

作为方法调用:

var ninja = {
    chirp: function(n) {
        return n > 1 ? ninja.chirp(n-1) + "-chirp" : "chirp";
    }
};

ninja.chirp(17905);

作为函数调用:

function chirp(n) {
    return n > 1 ? chirp( n - 1 ) + "-chirp" : "chirp";
}

chirp(20889);

s
spacedev

我也遇到了类似的问题,这里是使用下拉徽标上传框上传徽标时的详细信息

<div>
      <div class="uploader greyLogoBox" id="uploader" flex="64" onclick="$('#filePhoto').click()">
        <img id="imageBox" src="{{ $ctrl.companyLogoUrl }}" alt=""/>
        <input type="file" name="userprofile_picture"  id="filePhoto" ngf-select="$ctrl.createUploadLogoRequest()"/>
        <md-icon ng-if="!$ctrl.isLogoPresent" class="upload-icon" md-font-set="material-icons">cloud_upload</md-icon>
        <div ng-if="!$ctrl.isLogoPresent" class="text">Drag and drop a file here, or click to upload</div>
      </div>
      <script type="text/javascript">
          var imageLoader = document.getElementById('filePhoto');
          imageLoader.addEventListener('change', handleImage, false);

          function handleImage(e) {
              var reader = new FileReader();
              reader.onload = function (event) {

                  $('.uploader img').attr('src',event.target.result);
              }
              reader.readAsDataURL(e.target.files[0]);
          }
      </script>
      </div>

CSS.css

.uploader {
  position:relative;
  overflow:hidden;
  height:100px;
  max-width: 75%;
  margin: auto;
  text-align: center;

  img{
    max-width: 464px;
    max-height: 100px;
    z-index:1;
    border:none;
  }

  .drag-drop-zone {
    background: rgba(0, 0, 0, 0.04);
    border: 1px solid rgba(0, 0, 0, 0.12);
    padding: 32px;
  }
}

.uploader img{
  max-width: 464px;
  max-height: 100px;
  z-index:1;
  border:none;
}



.greyLogoBox {
  width: 100%;
  background: #EBEBEB;
  border: 1px solid #D7D7D7;
  text-align: center;
  height: 100px;
  padding-top: 22px;
  box-sizing: border-box;
}


#filePhoto{
  position:absolute;
  width:464px;
  height:100px;
  left:0;
  top:0;
  z-index:2;
  opacity:0;
  cursor:pointer;
}

在更正之前,我的代码是:

function handleImage(e) {
              var reader = new FileReader();
              reader.onload = function (event) {
                  onclick="$('#filePhoto').click()"
                  $('.uploader img').attr('src',event.target.result);
              }
              reader.readAsDataURL(e.target.files[0]);
          }

控制台中的错误:

https://i.stack.imgur.com/ZbGVS.png

我通过从 div 标签中删除 onclick="$('#filePhoto').click()" 解决了这个问题。


你在哪里添加 click()
我想回答,但系统建议先浏览旧的。是的,我的 HTML 中也有这个onclick="$obj.click()"。看起来它以某种方式循环 jquery 附件
T
Tajdar Khan Afridi

我遇到了同样的问题,我已经通过删除在 ajax 上使用过两次的字段名称来解决它,例如

    jQuery.ajax({
    url : '/search-result',
    data : {
      searchField : searchField,
      searchFieldValue : searchField,
      nid    :  nid,
      indexName : indexName,
      indexType : indexType
    },
.....

A
Amine Harbaoui

我的问题是因为我的子路由与父路由具有相同的路径:

const routes: Routes = [
  {
    path: '',
    component: HomeComponent,
    children: [
      { path: '', redirectTo: 'home', pathMatch: 'prefix' },
      { path: 'home', loadChildren: './home.module#HomeModule' },
    ]
  }
];

所以我不得不删除儿童路线的线路

const routes: Routes = [
  {
    path: '',
    component: HomeComponent,
    children: [
      { path: 'home', loadChildren: './home.module#HomeModule' },
    ]
  }
];

是的。我用这个解决了。我在 Angular 11 路线中进行了递归
V
Vishal Patel

您可以在 crome 浏览器中找到您的递归函数,按 ctrl+shift+j 然后源选项卡,它为您提供代码编译流程,您可以在代码中找到使用断点。


然而,有时很难找出错误的来源。我们的网站上有很多 JavaScript。
W
Weslley Ramos

我知道这个线程很旧,但我认为值得一提的是我发现这个问题的场景,以便它可以帮助其他人。

假设您有这样的嵌套元素:

<a href="#" id="profile-avatar-picker">
    <span class="fa fa-camera fa-2x"></span>
    <input id="avatar-file" name="avatar-file" type="file" style="display: none;" />
</a>

您不能在其父事件中操纵子元素事件,因为它会传播到自身,进行递归调用,直到抛出异常。

所以这段代码会失败:

$('#profile-avatar-picker').on('click', (e) => {
    e.preventDefault();

    $('#profilePictureFile').trigger("click");
});

您有两种选择可以避免这种情况:

将孩子移到父母的外面。

将 stopPropagation 函数应用于子元素。


M
Monir Tarabishi

我有这个错误是因为我有两个同名的 JS 函数


U
User-8017771

如果您使用的是 google 地图,请检查传入 new google.maps.LatLng 的 lat lng 格式是否正确。在我的情况下,它们被传递为未定义。


H
Hussein mahyoub

有时由于转换数据类型而发生,例如您有一个您认为是字符串的对象。

以js客户端为例,nodejs中的socket.id不是字符串。要将其用作字符串,您必须在之前添加单词 String:

String(socket.id);

a
asifaftab87

在我的情况下,我在 ajax 调用中收到此错误,并且我尝试传递该变量的数据尚未定义,这向我显示了此错误,但未描述未定义的变量。我添加了定义变量 n 的值。


我自己也以类似的方式被烧毁,就我而言,这是因为我输入了一个变量名……实际上是同一件事。
P
Phillip Quinlan

当尚未声明该变量时,我试图分配一个变量,一个值。

声明变量修复了我的错误。