繁体   English   中英

仅在 Firefox 中出现“递归过多”错误?

[英]A "too much recursion" error in Firefox only sometimes?

我正在用 javascript 做一件非常简单的事情,基本上只有有时 javascript 会给我一个“递归过多”错误。

有问题的代码:

if(pageLoad===undefined){
  var pageLoad=function(){}; 
}
var pageLoad_uniqueid_11=pageLoad;
var pageLoad=function(){ 
  pageLoad_uniqueid_11();
  pageLoad_uniqueid_12(); 
};
var pageLoad_uniqueid_12=function(){
 alert('pageLoad');
};

$(document).ready(function(){
   pageLoad();
});

(是的,我知道有更好的方法可以做到这一点。但这很难改变,特别是因为 ASP.Net 部分回发未显示)。

无论如何,当发生太多递归错误时,它会继续发生,直到我重新启动 Firefox。 当我重新启动 Firefox 时,一切都恢复正常。 我该如何解决?

我还做了一个jsbin 例子

更新

好的,我已经找到了如何在我们的代码中可靠地重现它,但它不适用于 jsbin 示例。 如果我创建一个新选项卡和 go 到同一页面(有两个相同地址的选项卡)然后刷新第一个选项卡两次,那么我会始终收到此错误。 我们没有使用任何类型的 session 或我能想到的任何其他可能导致此类问题仅出现在一个选项卡中的东西

更新 2不像我想象的那么可靠,但它肯定只在同一页面的多个选项卡打开时才会发生。 每隔几次重新加载打开的选项卡之一就会发生

我还更新了我的代码,以在 pageLoad(if 语句)最初未定义和最初定义时显示警报。 不知何故,两个警报都出现了。 此代码不会在呈现的页面中重复,并且不可能被调用两次。 它位于顶级脚本元素中,没有被 function 或任何东西包围我的代码最终看起来像

if(pageLoad===undefined){ 
  var pageLoad=function(){}; 
  alert('new'); 
} else {  
  alert('old'); 
}

有问题的代码 - 本身 - 永远不会导致无限递归问题 - 没有函数语句,并且所有函数对象都被急切地分配给变量。 (如果首页未定义pageload ,则会为其分配“无操作”功能,请参阅下一节。)

我怀疑还有其他代码/事件触发了这种行为。 可能导致它的一件事是在页面生命周期中脚本/代码被触发两次 第二次pageload不会被定义,并保留原始值,如果它是调用其他两个函数的函数,将导致无限递归。

我建议清理方法 - 并且由于并发症引起的任何问题都会消失;-)期望的意图是什么?

快乐的编码。

对于试图在代码中查找类似“过多递归”错误的其他人来说,这只是一些额外的信息。 看起来像firefox(作为一个例子)在这个例子中在大约6500个堆栈帧处得到太多的递归: function moose(n){if(n%100 === 0)console.log(n);moose(n+1)};moose(0) 类似的例子可以看到5000到7000之间的深度。不确定决定因素是什么,但似乎函数中的参数数量大大减少了堆栈帧深度,在这种情况下你会得到“过多的递归”错误。 例如,这只能达到3100:

function moose(n,m,a,s,d,fg,g,q,w,r,t,y,u,i,d){if(n%100 === 0)console.log(n);moose(n+1)};moose(0)

如果你想解决这个问题,你可以使用setTimeout来安排迭代从调度程序(它重置堆栈)继续。 这显然只有在您不需要从通话中返回内容时才有效:

function recurse(n) {
  if(n%100 === 0)
    setTimeout(function() {
      recurse(n+1)
    },0)
  else
    recurse(n+1)
}

ECMAScript 6中的正确尾部调用将解决您需要从此类调用返回内容的某些情况。 在此之前,对于具有深度递归的情况,唯一的答案是使用迭代或我提到的setTimeout方法。

我遇到了这个错误。 在我的情况下,情况是不同的。 罪魁祸首代码是这样的(这是简单的连接隐藏)

while(row)
{
    string_a .= row['name'];
}

我发现JavaScript在第180次递归时抛出错误。 直到179循环,代码运行正常。

Safaris中的行为完全相同,只是它显示的错误是“RangeError:超出最大调用堆栈大小”。 它也会在180递归时抛出此错误。

虽然这与函数调用无关,但它可能会帮助那些坚持使用它的人。

Afaik,如果您为ajax请求声明了错误的参数,也会出现此错误,例如

$.getJSON('get.php',{cmd:"1", elem:$('#elem')},function(data) { // ... }

那应该是什么

elem:$('#elem').val()

代替。

这也会导致“过多的递归”问题:

class account {
    constructor() {
        this.balance = 0;      // <-- property: balance
    }

    set balance( amount ) {    // <-- set function is the same name as the property.
        this.balance = amount; // <-- AND property: balance (unintended recursion here)
    }
}

var acc = new account();

使用唯一名称很重要。

好的,为什么会这样呢?

在set函数中,它实际上并没有将属性设置为amount,而是再次调用set函数,因为在set函数的范围内,它们设置属性AND调用set函数的语法相同。

因为在该范围内, thisaccount(account OR this).balance = amount既可以调用set函数,也可以设置属性。

解决方案是以任何方式简单地更改属性或set函数的名称(当然,相应地更新其余代码)。

升级我的Firefox后,我遇到了同样的错误。 似乎Firefox的版本会引起问题,因为当我在Chrome等其他浏览器中尝试时,它可以正常工作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM