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

我正在使用直接Web远程处理(DWR)JavaScript库文件,并且仅在Safari(桌面和iPad)中出现错误

上面写着

超出最大调用堆栈大小。

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

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

JS:执行超时

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

2013976 次浏览

你的代码中有一个递归循环(即一个函数最终会一次又一次地调用自己,直到堆栈满为止)。

其他浏览器要么有更大的堆栈(所以你会得到一个超时),要么出于某种原因(可能是一个糟糕的尝试捕获)吞下错误。

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

这意味着在您的代码中的某个地方,您正在调用一个函数,该函数又调用另一个函数等等,直到您达到调用堆栈限制。

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

查看堆栈

考虑这个代码…

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

这是经过几次调用后的堆栈…

网页检查器

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

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

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

如果您不小心导入/嵌入了两次相同的JavaScript文件,有时会出现这种情况,值得在检查器的资源选项卡中检查。

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

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

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

下面相同代码的两次调用如果减少1在我的计算机上Chrome32工作,例如17905 vs 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);

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

在我的例子中,我发送的是输入元素而不是它们的值:

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

而不是:

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

这冻结了我的Chrome选项卡,以至于当页面变得无响应时,它甚至没有向我显示“等待/杀死”对话框……

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

在我的例子中,单击事件在子元素上传播。所以,我必须放以下内容:

e.stop传播()

点击事件:

 $(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>

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

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

点击Performance tab,确保启用Javascript samples,你会得到这样的东西。

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

在此处输入图片描述

您还可以看到可能有帮助或可能没有帮助的时间或红鲱鱼。

在此处输入图片描述


如果你真的找不到问题,另一个有用的技巧是在你认为问题所在的地方放很多console.log语句。上面的上一步可以帮助你解决这个问题。

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

在此处输入图片描述

在我的例子中,我使用以下方法将大字节数组转换为字符串:

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

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

我也遇到过类似的问题 使用下拉徽标上传框上传徽标时

<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]);
}

控制台中的错误:

在此处输入图片描述

我通过从div标签中删除onclick="$('#filePhoto').click()"来解决它。

我也遇到了同样的问题 我通过删除在ajax上使用两次的字段名来解决它 e. g

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

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

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

<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");
});

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

  • 将子节点移到父节点的外部。
  • 停止传播函数应用于子元素。

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

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

有时发生是因为转换数据类型,例如您有一个被视为字符串的对象。

socket.id在nodejs或者在js客户端为例,是不是一个字符串.使用它作为字符串你必须添加字符串之前:

String(socket.id);

在我的情况下,问题是因为我有子路由与父路由具有相同的路径:

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' },
]
}
];

在我的情况下,我在ajax调用时遇到这个错误,我试图传递该变量的数据没有定义,这向我显示了这个错误,但没有描述那个未定义的变量。我添加了定义变量n得到了值。

我试图分配一个变量,一个值,当那个变量没有被声明时。

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

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

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

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

node --stack-size=2000

请参阅:如何在Node.js中增加最大调用堆栈大小

我们最近在我们正在开发的管理站点中添加了一个字段-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-问题解决了。

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

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

这里也一样:

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

Mozilla文档

但要注意:在使用应用这种方式,你运行的风险超过 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]);
}

遇到同样的问题,不知道怎么了,开始责怪巴别塔;)

在浏览器中没有返回任何异常的代码:

if (typeof document.body.onpointerdown !== ('undefined' || null)) {

问题创建得很糟糕||(或)部分,因为Babel创建了自己的类型检查:

function _typeof(obj){if(typeof Symbol==="function"&&_typeof(Symbol.iterator)==="symbol")

因此删除

|| null

使巴别塔转译工作。

我的情况 我错误地分配了相同的变量名,并为val函数“class_routine_id”

var class_routine_id = $("#class_routine_id").val(class_routine_id);

它应该像:

 var class_routine_id = $("#class_routine_id").val();

在Angular中,如果您使用mat-选择并且有400多个选项,则可能会出现此错误 https://github.com/angular/components/issues/12504

您必须更新@角/材料版本

我正在使用React-Native0.61.5和(npm 6.9.0&node 10.16.1

当我在Project中安装任何新库时,我得到了一个

(例如npm install@react-导航/本机--保存)

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

为此,我尝试

sudo npm缓存清理

(注意:-下面的命令通常需要1到2分钟的时间 根据您的npm缓存尺寸)

作为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
}
}

在我的情况下,我基本上忘记了inputvalue

错误

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

正确

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

当MongoDB数据库的模式和我们创建的模型不匹配时,我在Express/nodejs应用程序中遇到了这个错误。

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上使用的名称不同的名称。

在我的情况下,我有两个同名的变量!

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

有趣的是,在async函数中没有人提到wait call。在我的例子中,我有超过1.5 MB的带有循环和数据库交互的文件。

async function uploadtomongodb() {


await find('user', 'user2', myobj0).then(result => {
}


})

Await将删除“超出最大调用堆栈大小”。否则内存负载过多。不确定Node是否可以处理超过700行和对象。

该问题可能是因为递归调用没有任何终止的基本条件。

就像在我的例子中,如果您看到下面的代码,我的API调用方法和我用来执行API调用后操作的方法具有相同的名称。

const getData = async () => {
try {
const response = await getData(props.convID);
console.log("response", response);
} catch (err) {
console.log("****Error****", err);
}
};

所以,基本上,解决方案是删除此递归调用

在我的例子中,在app.module.ts,我得到了这个错误,因为我在导入和entryComponents中声明了组件。

Example:


import { MyComponent } from '....';


@NgModule({
declarations: [
MyComponent
],
imports: [
MyComponent  -- > remove this from here!!!!
],
providers: [],
bootstrap: [AppComponent],
entryComponents: [MyComponent]
})
export class AppModule { }