有时只在Firefox中出现“过多的递归”错误?

时间:2011-07-29 21:30:12

标签: javascript firefox recursion

我有一个非常简单的事情我正在使用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 example

更新

好的,我已经找到了如何在我们的代码中可靠地重现它,但它不适用于jsbin示例。如果我创建一个新选项卡并转到同一页面(有两个相同地址的选项卡),然后刷新第一个选项卡两次次,那么我会一致地得到此错误。我们没有使用任何类型的会话或其他任何我能想到的可能会导致这样的问题只出现在一个标签中的内容!

更新2 不像我想象的那么可靠,但它肯定只在同一页面的多个标签打开时才会出现。它会在其中一个选项卡的每次重新加载时打开

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

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

6 个答案:

答案 0 :(得分:7)

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

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

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

快乐的编码。

答案 1 :(得分:2)

这只是其他人试图寻找类似"过多递归的一些额外信息"他们的代码中的错误。看起来像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方法。

答案 2 :(得分:1)

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

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

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

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

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

答案 3 :(得分:0)

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

Meteor.methods({
 insertUserOnlineFlag:function(){
  UserOnlineFlag.insert({someOneOnline:true});
 },
 checkUserStatus:function(){
    var query = UserOnlineFlag.findOne();
    if(query){
    throw new Meteor.Error(403, "Already someone online");
    }else{
     return {message:"welcome to the stackoverflow question app"};
    }
  }
});

那应该是

"click .login":function(event, template){
     Meteor.call("checkUserStatus",function(){
       if(error){
            console.log(error.message);
        }else{
           console.log(result.message);
        }
     })
    }

代替。

答案 4 :(得分:0)

这还将导致“递归过多”问题:

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函数的范围内,设置属性和调用set函数的语法相同。 / p>

由于该范围thisaccount相同,并且(account OR this).balance = amount都可以调用set函数或设置属性。

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

答案 5 :(得分:-1)

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