Javascript 仅在 Firefox 中有时会出现“递归过多”错误?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6879238/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 23:36:06  来源:igfitidea点击:

A "too much recursion" error in Firefox only sometimes?

javascriptfirefoxrecursion

提问by Earlz

I have a pretty simple thing I'm doing with javascript and basically only sometimes will javascript give me a "too much recursion" error.

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

The code in question:

有问题的代码:

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

(yes I know there are better way of doing this. This is difficult to change though, especially because of ASP.Net partial postbacks which aren't shown).

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

Anyway, when the too much recursion error happens, it continues to happen until I restart Firefox. when I restart Firefox it all works as normal again. How do I fix this?

无论如何,当发生太多递归错误时,它会继续发生,直到我重新启动 Firefox。当我重新启动 Firefox 时,它再次正常工作。我该如何解决?

I've also made a jsbin example

我也做了一个jsbin 例子

Update

更新

Ok I've found out how to reliably reproduce it in our code, but it doesn't work for the jsbin example. If I create a new tab and go to the same page(have two tabs of the same address) and then refresh the first tab twotimes then I get this error consistently. We are not using any kind of session or anything else that I can think of that could cause such a problem to only occur in one tab!

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

Update 2Not as reliable as I thought, but it definitely only occurs when more than one tab of the same page is open. It'll occur every few reloads of one of the tabs open

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

I've also updated my code to show an alert when pageLoad(the if statement) is initially undefined and when it is initially defined. Somehow, both alerts are showing up. This code is not duplicated in the rendered page and there is no way that it is being called twice. It is in a top level script element not surrounded by a function or anything! My code ends up looking like

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

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

采纳答案by Earlz

The code in question -- by itself-- should neverresult in an infinite recursion issue -- there is no function-statement and all the function objects are eagerly assigned to the variables. (If pageloadis first undefined it will be assigned a No-Operation function, see next section.)

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

I suspect there is additional code/events that is triggering the behavior. One thing that maycause it is if the script/code is triggered twiceduring a page lifetime. The 2nd time pageloadwill not be undefined and will keep the original value, which if it is the function that calls the other two functions, will lead to infinite recursion.

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

I would recommend cleaning up the approach -- and having any issues caused by the complications just disappear ;-) What is the desired intent?

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

Happy coding.

快乐编码。

回答by B T

This is just some additional info for other people trying to look for similar "too much recursion" errors in their code. Looks like firefox (as an example) gets too much recursion at about 6500 stack frames deep in this example: function moose(n){if(n%100 === 0)console.log(n);moose(n+1)};moose(0). Similar examples can see depths of between 5000 and 7000. Not sure what the determining factors are, but it seems the number of parameters in the function drastically decrease the stack frame depth at which you get a "too much recursion" error. For example, this only gets to 3100:

这只是其他人试图在他们的代码中寻找类似的“递归过多”错误的一些附加信息。喜欢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)

If you want to get around this, you can use setTimeout to schedule iterations to continue from the scheduler (which resets the stack). This obviously only works if you don't need to return something from the call:

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

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

Proper tail calls in ECMAScript 6 will solve the problem for some cases where you do need to return something from calls like this. Until then, for cases with deep recursion, the only answers are using either iteration, or the setTimeoutmethod I mentioned.

ECMAScript 6 中正确的尾调用将解决某些情况下的问题,在这种情况下,您确实需要从这样的调用中返回某些内容。在那之前,对于深度递归的情况,唯一的答案是使用迭代或setTimeout我提到的方法。

回答by Hammad Khan

I came across this error. The scenario in my case was different. The culprit code was something like this (which is simple concatenation recessively)

我遇到了这个错误。我的情况是不同的。罪魁祸首是这样的(这是简单的隐性连接)

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

I found that JavaScript throws error on 180th recursion. Up till 179 loop, the code runs fine.

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

The behaviors in Safaris is exactly the same, except that the error it shows is "RangeError: Maximum call stack size exceeded." It throws this error on 180 recursion as well.

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

Although this is not related to function call but it might help somebody who are stuck with it.

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

回答by Sebastian Norr

This will also cause the "too much recursion" issue:

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

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();

Using unique names is important.

使用唯一的名称很重要。

Ok, so why is this happening?

好的,为什么会发生这种情况?

In the set function it isn't actually setting the property to amount, instead it's calling the set function again because in the scope of the set function it is the same syntax for both setting the property AND calling the set function.

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

Because in that scope thisis the same as accountand (account OR this).balance = amountcan both call the set function OR set the property.

因为在那个范围this是一样的account,并(account OR this).balance = amount能都调用设定功能或设置属性。

The solution to this is to simply change the name of either the property or the set function in any way (and of course update the rest of the code accordingly).

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

回答by phil294

Afaik, this error can also appear if you state a wrong parameter for your ajax request, like

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

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

Which then should be

那应该是

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

instead.

反而。

回答by ddsultan

I have got the same error after upgrading my Firefox. It seems that the version of Firefox causes issue, since when I tried in other browsers like Chrome it works OK.

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