La dimensione massima dello stack di chiamate ha superato l'errore


533

Sto utilizzando un file di libreria JavaScript Direct Web Remoting (DWR) e visualizzo un errore solo in Safari (desktop e iPad)

Dice

Dimensione massima dello stack di chiamate superata.

Cosa significa esattamente questo errore e interrompe l'elaborazione completamente?

Anche qualsiasi correzione per il Safaribrowser (in realtà sul iPad Safari, dice

JS: esecuzione superata timeout

che presumo sia lo stesso problema di stack di chiamate)


2
ho riscontrato questo errore nel tentativo di inviare variabili (senza dichiararle), tramite dataajax. Risolto l'errore dichiarando le variabili.
phpfresher,

Risposte:


621

Significa che da qualche parte nel tuo codice, stai chiamando una funzione che a sua volta chiama un'altra funzione e così via, fino a quando non raggiungi il limite dello stack di chiamate.

Questo è quasi sempre a causa di una funzione ricorsiva con un caso base che non viene soddisfatto.

Visualizza la pila

Considera questo codice ...

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

Ecco lo stack dopo una manciata di chiamate ...

Ispettore Web

Come puoi vedere, lo stack di chiamate cresce fino a raggiungere un limite: le dimensioni dello stack codificato dal browser o l'esaurimento della memoria.

Per risolverlo, assicurati che la tua funzione ricorsiva abbia un caso base che possa essere soddisfatto ...

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

6
Grazie mille per quello ... Quindi c'è qualche modo / strumento con cui posso esaurire il limite dello stack ... Di nuovo, dato che si tratta di un file di libreria enorme e non creato da me, non sono completamente consapevole di dove le cose potrebbero andare male ..
testndtv,

52
@Oliver Se devi eseguire una funzione quasi 300 trilioni di volte, probabilmente stai facendo qualcosa di sbagliato.
Ceejayoz,

3
@Oliver - potresti voler esaminare la programmazione dinamica - suppongo che tu non abbia molte soluzioni uniche, stai ripetendo i passaggi, quindi potresti aver bisogno di programmarlo in modo che sia polinumiale piuttosto che quadratico. en.wikipedia.org/wiki/Dynamic_programming
newshorts

4
@Akhoy In una funzione regolare sì, ma pensa a una funzione ricorsiva. Chiama un altro (se stesso) e lascia nello stack l'indirizzo di ritorno del primo (altrimenti dove il PC saprebbe dove andare?) Questo ovviamente si richiama di nuovo, ogni volta spingendo un indirizzo di ritorno nello stack. Quando questo si esaurisce a causa di un caso di base che probabilmente non sarà soddisfatto nel prossimo secolo, si ottiene un overflow dello stack.
alex

5
Il codice esegue lo stesso segmento inefficiente 134217728 volte. Non sto scherzando è lento. Dovresti usare operatori bit per bit in modo da poter srotolare i 9 livelli di loop in un livello di loop.
Jack Giffin,

82

A volte puoi ottenerlo se importi / incorpori accidentalmente lo stesso file JavaScript due volte, vale la pena controllare nella scheda Risorse della finestra di ispezione.


9
Questo problema si verifica in genere quando si importa / incorpora accidentalmente lo stesso file JS due volte. Il processo esatto che provoca il circuito ricorsivo non è qualcosa su cui mi interessa speculare, tuttavia suppongo che sia qualcosa come guidare due auto identiche a 100 miglia all'ora attraverso lo stesso gateway a pedaggio.
lucygenik,

3
Non penso che sia così. Se sono incorporati due stessi tipi di funzioni o variabili, quest'ultima sovrascriverà le definizioni precedenti.
ssudaraka,

Sì ... Non so davvero perché accada o quale sia il processo, avrei pensato che avrebbe avuto la precedenza.
lucygenik,

Un po 'tardi per la festa, ma immaginerebbe che è quando il codice è al di fuori di qualsiasi funzione, entrambi verrebbero eseguiti all'interno dei due file JS e uno probabilmente non si sovrascriverebbe a vicenda poiché sono al di fuori di qualsiasi funzione.
Cillian Collins,

1
@lucygenik la prossima volta che vuoi stare più attento quando approvi le modifiche al troll sui tuoi post. Questo post è stato quasi cancellato come spam (controlla la cronologia)
Jean-François Fabre

57

Nel mio caso, stavo inviando elementi di input anziché i loro valori:

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

Invece di:

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

Questo ha bloccato la mia scheda Chrome fino a un punto in cui non mi ha nemmeno mostrato la finestra di dialogo "Aspetta / Uccidi" per quando la pagina non ha risposto ...


3
Mi chiedo perché non ci sia un'eccezione per tale errore ... Grazie!
Džuris,

Grazie mille, questo mi ha salvato
Eme Hado

Stavo per aggiungere questo come possibile soluzione. Ho appena fatto questa cosa esatta lol
Michael Buchok il

31

C'è un ciclo ricorsivo da qualche parte nel tuo codice (cioè una funzione che alla fine si chiama più e più volte fino a quando lo stack è pieno).

Altri browser hanno stack più grandi (quindi si ottiene un timeout invece) o inghiottono l'errore per qualche motivo (forse un try-catch posizionato male).

Utilizzare il debugger per controllare lo stack di chiamate quando si verifica l'errore.


Grazie mille per la tua risposta. Su IE / FF, il codice sembra funzionare bene. Solo su Safari desktop e iPad Safari, ottengo l'errore. In realtà il file JS non è una mia creazione, ma è un file di libreria (da DWR engine.js) .. directwebremoting.org Anche quando dici "debugger per controllare lo stack di chiamate", come posso farlo usando Safari Inspector?
testndtv,

Non ho esperienza con Safari Inspector. Prova ad aprire il debugger JavaScript e carica la tua pagina. Il debugger dovrebbe arrestarsi quando viene generato un errore non corretto. Se il
problema persiste

aveva 2 funzioni chiamate la stessa cosa !! DOH!
jharris8567,

16

Il problema con il rilevamento di stackoverflow è che a volte la traccia dello stack si svolgerà e non sarai in grado di vedere cosa sta realmente succedendo.

Ho trovato utili alcuni dei più recenti strumenti di debug di Chrome.

Premi il Performance tab, assicurati che Javascript samplessiano abilitati e otterrai qualcosa del genere.

È abbastanza ovvio dove si trova l'overflow! Se fai clic su extendObject, sarai in grado di vedere esattamente il numero di riga nel codice.

inserisci qui la descrizione dell'immagine

Puoi anche vedere i tempi che possono essere utili o meno o un'aringa rossa.

inserisci qui la descrizione dell'immagine


Un altro trucco utile se non riesci effettivamente a trovare il problema è quello di mettere un sacco di console.log affermazioni dove pensi che sia il problema. Il passaggio precedente sopra può aiutarti in questo.

In Chrome, se si emettono ripetutamente dati identici, verranno visualizzati in questo modo, mostrando dove il problema è più chiaro. In questo caso lo stack ha colpito 7152 frame prima che si schiantasse alla fine:

inserisci qui la descrizione dell'immagine


13

Nel mio caso, stavo convertendo un array di byte di grandi dimensioni in una stringa utilizzando quanto segue:

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

bytes conteneva diversi milioni di voci, che è troppo grande per stare nello stack.


Anch'io ho avuto lo stesso problema con la stessa linea !! grazie
ksh,

quindi qual è la soluzione migliore per convertire array di byte di grandi dimensioni ??
ksh,

6
@KarthikHande Devi farlo in un ciclo for anziché in una chiamata. var uintArray = new Uint16Array(bytes); var converted = []; uintArray.forEach(function(byte) {converted.push(String.fromCharCode(byte))});
Nate Glenn,

come posso convertirlo in JSON? Ho provato JSON.parse ma non ha funzionato ... Sto usando Uintl8Array
ksh il

@KarthikHande Non posso dirlo senza vedere l'intero problema. Si prega di aprire un'altra domanda con tutti i dettagli.
Nate Glenn,

6

Nel mio caso, l'evento click si stava propagando sull'elemento figlio. Quindi, ho dovuto mettere quanto segue:

e.stopPropagation ()

evento al clic:

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

Ecco il codice html:

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

5

Controlla i dettagli dell'errore nella console della barra degli strumenti di sviluppo di Chrome, questo ti darà le funzioni nello stack di chiamate e ti guiderà verso la ricorsione che causa l'errore.



3

Quasi ogni risposta qui afferma che ciò può essere causato solo da un ciclo infinito. Questo non è vero, altrimenti potresti sovraccaricare lo stack attraverso chiamate profondamente annidate (per non dire che è efficiente, ma è certamente nel regno del possibile). Se hai il controllo della tua VM JavaScript, puoi regolare le dimensioni dello stack. Per esempio:

node --stack-size=2000

Vedi anche: Come posso aumentare la dimensione massima dello stack di chiamate in Node.js


2

Nel mio caso, due modali jQuery sono state mostrate sovrapposte. Prevenire ciò ha risolto il mio problema.


2

Di recente abbiamo aggiunto un campo a un sito di amministrazione su cui stiamo lavorando - contact_type ... easy right? Bene, se chiami il "tipo" selezionato e provi a inviarlo tramite una chiamata ajax jquery fallisce con questo errore sepolto in profondità in jquery.js Non farlo:

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

Il problema è quel tipo: tipo - credo che siamo noi a nominare l'argomento "tipo" - avere una variabile di valore chiamata tipo non è il problema. Abbiamo cambiato questo in:

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

E riscritto some_function.php di conseguenza - problema risolto.


1

Controlla se hai una funzione che si chiama da sola. Per esempio

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

1

Ciò può anche causare un Maximum call stack size exceedederrore:

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

Anch'io:

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

Dai documenti di Mozilla :

Ma attenzione: nell'uso di applicare in questo modo, si corre il rischio di superare il limite di lunghezza degli argomenti del motore JavaScript. Le conseguenze dell'applicazione di una funzione con troppi argomenti (pensa più di decine di migliaia di argomenti) variano a seconda dei motori (JavaScriptCore ha un limite di argomenti codificato a 65536), perché il limite (anzi persino la natura di uno stack eccessivamente grande comportamento) non è specificato. Alcuni motori genereranno un'eccezione. Più perniciosamente, altri limiteranno arbitrariamente il numero di argomenti effettivamente passati alla funzione applicata. Per illustrare quest'ultimo caso: se un tale motore avesse un limite di quattro argomenti (i limiti effettivi sono ovviamente significativamente più alti), sarebbe come se gli argomenti 5, 6, 2, 3 fossero stati passati per applicarsi negli esempi precedenti, piuttosto che l'array completo.

Allora prova:

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

0

Entrambe le invocazioni dello stesso identico codice riportato di seguito se diminuite di 1 funzionano in Chrome 32 sul mio computer, ad es. 17905 vs 17904. Se eseguito così com'è, genererà l'errore "RangeError: Dimensione massima dello stack di chiamate superata". Sembra che questo limite non sia hardcoded ma dipendente dall'hardware del tuo computer. Sembra che se invocato come funzione questo limite autoimposto è maggiore di se invocato come metodo, cioè questo particolare codice usa meno memoria quando viene invocato come funzione.

Richiamato come metodo:

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

ninja.chirp(17905);

Richiamato come funzione:

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

chirp(20889);

0

puoi trovare la tua funzione ricorsiva nel browser crome, premere ctrl + shift + j e quindi la scheda sorgente, che ti dà il flusso di compilazione del codice e puoi trovare usando il punto di interruzione nel codice.


A volte, tuttavia, può essere difficile capire l'origine dell'errore. Abbiamo MOLTO JavaScript sul nostro sito.
Mathias Lykkegaard Lorenzen,

0

Ho anche riscontrato problemi simili qui sono i dettagli quando si carica il logo utilizzando la casella di caricamento del logo a discesa

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

prima della correzione il mio codice 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]);
          }

L'errore nella console:

inserisci qui la descrizione dell'immagine

L'ho risolto rimuovendo onclick="$('#filePhoto').click()"dal tag div.


Dove hai aggiunto il clic ()
Tsea

0

Stavo affrontando lo stesso problema che ho risolto rimuovendo un nome di campo che è stato usato due volte su Ajax ad es

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

0

So che questo thread è vecchio, ma penso che valga la pena menzionare lo scenario in cui ho riscontrato questo problema in modo che possa aiutare gli altri.

Supponiamo di avere elementi nidificati come questo:

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

Non è possibile manipolare gli eventi dell'elemento figlio all'interno dell'evento del suo genitore perché si propaga a se stesso, effettuando chiamate ricorsive fino a quando non viene generata l'eccezione.

Quindi questo codice fallirà:

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

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

Hai due opzioni per evitare questo:

  • Sposta il bambino all'esterno del genitore.
  • Applica la funzione stopPropagation all'elemento figlio.


0

Se stai lavorando con google maps, controlla se il lat lng viene passato nel new google.maps.LatLngformato corretto. Nel mio caso venivano passati come indefiniti.


0

Il problema nel mio caso è perché ho percorso figlio con lo stesso percorso con il genitore:

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

Quindi ho dovuto rimuovere la linea del percorso dei bambini

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

0

nel mio caso sto ricevendo questo errore su una chiamata Ajax e i dati che ho provato a passare quella variabile non sono stati definiti, questo mi sta mostrando questo errore ma non sta descrivendo quella variabile non definita. Ho aggiunto definito che la variabile n ha ottenuto valore.


mi sono bruciato in un modo simile, nel mio caso è stato perché ho digitato un nome variabile ... effettivamente la stessa cosa.
user2366842

0

Si sono imbattuti nello stesso problema, non è stato possibile capire cosa c'è che non ha iniziato a incolpare Babel;)

Avere codice che non restituisce alcuna eccezione nei browser:

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

il problema è stato creato male || (o) parte come babel crea il proprio controllo del tipo:

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

così rimuovendo

|| null

fatto funzionare la transpilazione della babele.


0

Nel mio caso, per errore, ho assegnato lo stesso nome di variabile e alla funzione val "class_routine_id"

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

dovrebbe essere come:

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


0

Sto usando React-Native 0.61.5 insieme a ( npm 6.9.0 e nodo 10.16.1 )

Mentre sto installando tutte le nuove librerie in Project ho ottenuto un

(ad es. npm install @ reply-navigation / native --save)

La dimensione massima dello stack di chiamate ha superato l'errore

per quello, ci provo

sudo npm cache clean --force

(Nota: - Sotto il comando di solito impiegano da 1 a 2 minuti a seconda della dimensione della cache npm )


-1

A volte è successo a causa del tipo di dati convertito, ad esempio hai un oggetto che hai considerato stringa.

socket.id in nodejs o nel client js come esempio, non è una stringa. per usarlo come stringa devi aggiungere la parola String prima di:

String(socket.id);

-1

Stavo cercando di assegnare una variabile, un valore, quando quella variabile non era stata dichiarata.

Dichiarare la variabile ha corretto il mio errore.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.