O tamanho máximo da pilha de chamadas excedeu o erro

533

Estou usando um arquivo de biblioteca JavaScript do Direct Web Remoting (DWR) e estou recebendo um erro apenas no Safari (desktop e iPad)

Diz

Tamanho máximo da pilha de chamadas excedido.

O que exatamente esse erro significa e para de processar completamente?

Também qualquer correção para o Safarinavegador (na verdade iPad Safari, diz

JS: execução excedeu o tempo limite

presumo que seja o mesmo problema da pilha de chamadas)

testndtv
fonte
2
Eu recebi esse erro ao tentar enviar variáveis ​​(sem declará-las), através datado ajax. Corrigido o erro declarando as variáveis.
Phpfresher # 1 de

Respostas:

621

Isso significa que, em algum lugar do seu código, você está chamando uma função que, por sua vez, chama outra função e assim por diante, até atingir o limite da pilha de chamadas.

Isso ocorre quase sempre por causa de uma função recursiva com um caso base que não está sendo atendido.

Visualizando a pilha

Considere este código ...

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

Aqui está a pilha após um punhado de chamadas ...

Inspetor da Web

Como você pode ver, a pilha de chamadas cresce até atingir um limite: o tamanho da pilha codificada pelo navegador ou o esgotamento da memória.

Para corrigi-lo, verifique se sua função recursiva possui um caso base que pode ser atendido ...

(function a(x) {
    // The following condition 
    // is the base case.
    if ( ! x) {
        return;
    }
    a(--x);
})(10);
alex
fonte
6
Thx muito para isso .. Então, existe alguma maneira / ferramenta pela qual eu posso que o limite de pilha está sendo esgotado .. Novamente, como este é um enorme arquivo de biblioteca e não foi criado por mim, não estou completamente ciente de onde as coisas podem estar indo mal ..
testndtv 23/05
52
@ Oliver Se você precisar executar uma função quase 300 trilhões de vezes, provavelmente está fazendo algo errado.
precisa
3
@ Oliver - você pode querer olhar para programação dinâmica - meu palpite é que você não tem muitas soluções exclusivas, está repetindo etapas, portanto, pode ser necessário programá-lo para que seja um tempo polinumial e não quadrático. pt.wikipedia.org/wiki/Dynamic_programming
newshorts
4
@ Akhoy Em uma função regular, sim, mas pense em uma função recursiva. Ele chama outro (ele mesmo) e deixa o endereço de retorno do antigo na pilha (caso contrário, para onde o PC saberia para onde ir?) Isso obviamente se chama novamente, cada vez que coloca um endereço de retorno na pilha. Quando isso ocorre devido a um caso básico que provavelmente não será atendido no próximo século, você terá um estouro de pilha.
19416 alex
5
Seu código executa o mesmo segmento ineficiente 134217728 vezes. Sem brincadeira é lento. Você deve usar operadores bit a bit para poder desenrolar os 9 níveis de loops em um nível de loops.
precisa
82

Às vezes, você pode obtê-lo se importar / incorporar acidentalmente o mesmo arquivo JavaScript duas vezes, vale a pena conferir na guia de recursos do inspetor.

lucygenik
fonte
9
Esse problema geralmente ocorre quando você importa / incorpora acidentalmente o mesmo arquivo JS duas vezes. O processo exato que causa o loop recursivo não é algo que eu gostaria de especular, mas eu diria que é algo como dirigir dois carros idênticos a 100 km / h através do mesmo pedágio.
lucygenik
3
Não acho que seja esse o caso. Se dois tipos iguais de funções ou variáveis ​​forem incorporados, o último substituirá as definições anteriores.
Ssudaraka
Sim ... eu realmente não sei por que isso acontece ou qual é o processo, eu teria que substituir também.
lucygenik
Um pouco atrasado para a festa, mas imaginamos que quando o código estiver fora de qualquer função, ambos serão executados nos dois arquivos JS e um provavelmente não será substituído, pois está fora de qualquer função.
Cillian Collins
1
@lucygenik da próxima vez que você quiser ter mais cuidado ao aprovar edições trolls em suas postagens. Esta postagem quase foi excluída como spam (verificar histórico)
Jean-François Fabre
57

No meu caso, eu estava enviando elementos de entrada em vez de seus valores:

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

Ao invés de:

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

Isso congelou minha guia do Chrome a um ponto em que nem me mostrou a caixa de diálogo 'Aguardar / Matar' para quando a página não respondesse ...

FKasa
fonte
3
Gostaria de saber por que não há uma exceção para esse erro ... Obrigado!
26618 Džuris
Muito obrigado, isso me salvou
Eme Hado /
Eu estava prestes a adicionar isso como uma possível solução. Eu apenas fiz exatamente isso lol
Michael Buchok 10/04
31

Existe um loop recursivo em algum lugar do seu código (ou seja, uma função que eventualmente se chama repetidamente até que a pilha esteja cheia).

Outros navegadores têm pilhas maiores (então você recebe um tempo limite) ou engolem o erro por algum motivo (talvez um try-catch mal colocado).

Use o depurador para verificar a pilha de chamadas quando o erro ocorrer.

Aaron Digulla
fonte
Muito obrigado pela sua resposta. No IE / FF, o código parece funcionar bem. Somente no Safari de área de trabalho e no iPad Safari, recebo o erro. Na verdade, o arquivo JS não é de minha própria criação, mas é um arquivo de biblioteca (do DWR engine.js) .. directwebremoting.org Além disso, quando você diz "depurador para verificar a pilha de chamadas", como faço isso usando o Safari Inspector?
Testndtv 23/05
Não tenho experiência com o Safari Inspector. Tente abrir o depurador JavaScript e carregar sua página. O depurador deve parar quando um erro não corrigido é lançado. Se isso não funcionar, pergunte sobre superusuário ou webmasters (ver final da página)
Aaron Digulla
tinha 2 funções nomeadas a mesma coisa !! DOH!
precisa saber é o seguinte
16

O problema com a detecção de fluxos de empilhamento às vezes é que o rastreio da pilha se desenrola e você não consegue ver o que realmente está acontecendo.

Encontrei algumas das ferramentas de depuração mais recentes do Chrome úteis para isso.

Clique no Performance tab, verifique se Javascript samplesestá ativado e você obterá algo assim.

É bastante óbvio onde o estouro está aqui! Se você clicar em, extendObjectpoderá ver o número exato da linha no código.

insira a descrição da imagem aqui

Você também pode ver horários que podem ou não ser úteis ou um arenque vermelho.

insira a descrição da imagem aqui


Outro truque útil, se você realmente não consegue encontrar o problema, é colocar muitas console.loginstruções onde você acha que está o problema. A etapa anterior acima pode ajudá-lo com isso.

No Chrome, se você gerar repetidamente dados idênticos, ele será exibido dessa maneira, mostrando onde o problema é mais claro. Nesse caso, a pilha atingiu 7152 quadros antes de finalmente travar:

insira a descrição da imagem aqui

Simon_Weaver
fonte
13

No meu caso, eu estava convertendo uma matriz de bytes grandes em uma string usando o seguinte:

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

bytes continha vários milhões de entradas, que são grandes demais para caber na pilha.

Nate Glenn
fonte
Eu também tive o mesmo problema com a mesma linha !! thanx
ksh
Então, qual é a melhor solução para converter uma matriz de bytes grandes ??
Ksh 5/17
6
@KarthikHande Você precisa fazer isso em um loop for em vez de em uma chamada. var uintArray = new Uint16Array(bytes); var converted = []; uintArray.forEach(function(byte) {converted.push(String.fromCharCode(byte))});
Nate Glenn
como faço para convertê-lo em JSON Tentei JSON.parse mas não funcionou ... Eu estou usando Uintl8Array?
ksh
@KarthikHande eu não posso dizer sem ver todo o problema. Por favor, abra outra pergunta com todos os detalhes.
Nate Glenn
6

No meu caso, o evento click foi propagado no elemento filho. Então, eu tive que colocar o seguinte:

e.stopPropagation ()

no evento de clique:

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

Aqui está o código html:

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

Verifique os detalhes do erro no console da barra de ferramentas do desenvolvedor do Chrome, isso fornecerá as funções na pilha de chamadas e o guiará para a recursão que está causando o erro.

chim
fonte
3

Quase todas as respostas aqui afirmam que isso só pode ser causado por um loop infinito. Isso não é verdade, você poderia sobrecarregar a pilha por meio de chamadas profundamente aninhadas (para não dizer que é eficiente, mas certamente está no campo possível). Se você tem controle da sua VM JavaScript, pode ajustar o tamanho da pilha. Por exemplo:

node --stack-size=2000

Consulte também: Como posso aumentar o tamanho máximo da pilha de chamadas no Node.js

ghayes
fonte
2

No meu caso, dois modais jQuery estavam aparecendo empilhados uns sobre os outros. Prevenir isso resolveu meu problema.

Barry Guvenkaya
fonte
2

Recentemente, adicionamos um campo ao site de administração em que estamos trabalhando - contact_type ... fácil, certo? Bem, se você chamar o select "type" e tentar enviá-lo através de uma chamada jquery ajax, ele falhará com esse erro oculto no jquery.js Não faça isso:

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

O problema é esse tipo: type - acredito que estamos nomeando o argumento "type" - ter uma variável de valor chamada type não é o problema. Alteramos isso para:

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

E reescrevi some_function.php de acordo - problema resolvido.

Scott
fonte
1

Verifique se você tem uma função que se chama. Por exemplo

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

Isso também pode causar um Maximum call stack size exceedederro:

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

O mesmo aqui:

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

No Mozilla Docs :

Mas tenha cuidado: ao usar o método aplicar desta maneira, você corre o risco de exceder o limite de tamanho do argumento do mecanismo JavaScript. As conseqüências da aplicação de uma função com muitos argumentos (pense em mais de dezenas de milhares de argumentos) variam entre os mecanismos (JavaScriptCore possui um limite de argumento codificado de 65536), porque o limite (na verdade, mesmo a natureza de qualquer pilha excessivamente grande) comportamento) não é especificado. Alguns motores lançam uma exceção. Mais perniciosamente, outros limitarão arbitrariamente o número de argumentos realmente transmitidos à função aplicada. Para ilustrar esse último caso: se um mecanismo desse tipo tivesse um limite de quatro argumentos (os limites reais são obviamente significativamente mais altos), seria como se os argumentos 5, 6, 2, 3 tivessem sido passados ​​para aplicar nos exemplos acima, em vez de toda a matriz.

Então tente:

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

Ambas as invocações do código idêntico abaixo se diminuídas em 1 trabalho no Chrome 32 no meu computador, por exemplo, 17905 vs 17904. Se executadas como estão, produzirão o erro "RangeError: tamanho máximo da pilha de chamadas excedido". Parece que esse limite não é codificado, mas depende do hardware da sua máquina. Parece que se invocado como uma função, esse limite auto-imposto é mais alto do que se invocado como um método, ou seja, esse código específico usa menos memória quando invocado como uma função.

Chamado como um método:

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

ninja.chirp(17905);

Chamado como uma função:

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

chirp(20889);
Elijah Lynn
fonte
0

você pode encontrar sua função recursiva no navegador crome, pressione ctrl + shift + j e, em seguida, na guia fonte, que fornece fluxo de compilação de código e você pode encontrar usando o ponto de interrupção no código.

Vishal Patel
fonte
Às vezes, no entanto, pode ser difícil descobrir onde o erro se originou. Temos muito JavaScript em nosso site.
Mathias Lykkegaard Lorenzen
0

Também enfrentei um problema semelhante. Aqui estão os detalhes ao fazer o upload do logotipo usando a caixa suspensa de upload do logotipo

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

antes da correção, meu código era:

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

O erro no console:

insira a descrição da imagem aqui

Eu o resolvi removendo onclick="$('#filePhoto').click()"da tag div.

spacedev
fonte
Onde você adicionou o clique ()
Tsea 04/10
0

Eu estava enfrentando o mesmo problema que resolvi removendo um nome de campo que foi usado duas vezes no ajax, por exemplo

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

Eu sei que esse tópico é antigo, mas acho que vale a pena mencionar o cenário em que encontrei esse problema para que ele possa ajudar outras pessoas.

Suponha que você tenha elementos aninhados como este:

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

Você não pode manipular os eventos do elemento filho dentro do evento de seu pai porque ele se propaga para si mesmo, fazendo chamadas recursivas até que a exceção seja lançada.

Portanto, este código falhará:

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

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

Você tem duas opções para evitar isso:

  • Mova o filho para fora dos pais.
  • Aplique a função stopPropagation ao elemento filho.
Weslley Ramos
fonte
0

Eu tive esse erro porque eu tinha duas funções JS com o mesmo nome

Dragão de Gelo
fonte
0

Se você estiver trabalhando com o Google Maps, verifique se a latência está sendo passada para new google.maps.LatLngo formato correto. No meu caso, eles estavam sendo passados ​​como indefinidos.

User-8017771
fonte
0

O problema no meu caso é porque eu tenho filhos roteados com o mesmo caminho do pai:

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

Então eu tive que remover a linha da rota das crianças

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

no meu caso, estou recebendo esse erro na chamada ajax e os dados que tentei passar nessa variável não foram definidos, isso está me mostrando esse erro, mas não descrevendo a variável não definida. Eu adicionei definiu que a variável n obteve valor.

asifaftab87
fonte
me queimei de maneira semelhante, no meu caso foi porque eu digitei um nome de variável ... efetivamente a mesma coisa.
user2366842
0

Chegaram ao mesmo problema, mas não descobriram o que havia de errado e começou a culpar Babel;)

Tendo o código não retornando nenhuma exceção nos navegadores:

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

problema foi mal criado || (ou) parte como babel cria sua própria verificação de tipo:

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

então removendo

|| null

fez a transpilação de babel funcionar.

Rafael
fonte
0

No meu caso, por engano, atribuí o mesmo nome de variável e à função val "class_routine_id"

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

deve ser como:

 var class_routine_id = $("#class_routine_id").val(); 
Alok Jha
fonte
0

Estou usando o React-Native 0.61.5 junto com ( npm 6.9.0 e nó 10.16.1 )

Enquanto instalo novas bibliotecas no Project, recebi um

(por exemplo, npm install @ react-navigation / native --save)

O tamanho máximo da pilha de chamadas excedeu o erro

por isso, eu tento

sudo npm cache clean --force

(Nota: - O comando abaixo normalmente leva de 1 a 2 minutos, dependendo do tamanho do cache npm )

DevAelius
fonte
-1

Às vezes, acontecia por causa do tipo de dado de conversão, por exemplo, você tem um objeto que considerou como string.

socket.id no nodejs, no cliente js, por exemplo, não é uma sequência. Para usá-lo como string, você deve adicionar a palavra String antes:

String(socket.id);
Hussein mahyoub
fonte
-1

Eu estava tentando atribuir uma variável, um valor, quando essa variável não havia sido declarada.

Declarar a variável corrigiu meu erro.

Phillip Quinlan
fonte