Die maximale Größe des Aufrufstapels hat den Fehler überschritten

533

Ich verwende eine Direct Web Remoting (DWR) -JavaScript-Bibliotheksdatei und erhalte nur in Safari (Desktop und iPad) eine Fehlermeldung.

Es sagt

Maximale Call-Stack-Größe überschritten.

Was genau bedeutet dieser Fehler und stoppt er die Verarbeitung vollständig?

Auch irgendein Fix für den SafariBrowser (Eigentlich auf dem iPad Safari, heißt es

JS: Die Ausführung hat das Zeitlimit überschritten

Ich gehe davon aus, dass es sich um dasselbe Call-Stack-Problem handelt.

testndtv
quelle
2
Ich habe diesen Fehler beim Versuch, Variablen (ohne sie zu deklarieren) datain Ajax durch zu senden . Der Fehler wurde durch Deklarieren der Variablen behoben.
Phpfresher

Antworten:

621

Dies bedeutet, dass Sie irgendwo in Ihrem Code eine Funktion aufrufen, die wiederum eine andere Funktion usw. aufruft, bis Sie das Aufrufstapellimit erreicht haben.

Dies liegt fast immer an einer rekursiven Funktion mit einem Basisfall, der nicht erfüllt wird.

Stapel anzeigen

Betrachten Sie diesen Code ...

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

Hier ist der Stapel nach einer Handvoll Aufrufen ...

Web Inspector

Wie Sie sehen können, wächst der Aufrufstapel, bis er ein Limit erreicht: die fest codierte Stapelgröße des Browsers oder die Speicherauslastung.

Um dies zu beheben, stellen Sie sicher, dass Ihre rekursive Funktion einen Basisfall hat, der erfüllt werden kann ...

(function a(x) {
    // The following condition 
    // is the base case.
    if ( ! x) {
        return;
    }
    a(--x);
})(10);
Alex
quelle
6
Vielen Dank dafür. Es gibt also eine Möglichkeit / ein Werkzeug, mit dem ich das Stapellimit ausschöpfen kann. Da dies eine riesige Bibliotheksdatei ist und nicht von mir erstellt wurde, weiß ich nicht genau, wo Dinge könnten schief gehen ..
testndtv
52
@Oliver Wenn Sie eine Funktion fast 300 Billionen Mal ausführen müssen, machen Sie wahrscheinlich etwas falsch.
Ceejayoz
3
@Oliver - vielleicht möchten Sie sich mit dynamischer Programmierung befassen - ich vermute, Sie haben nicht so viele einzigartige Lösungen, Sie wiederholen Schritte, daher müssen Sie sie möglicherweise so programmieren, dass sie polynumial und nicht quadratisch ist. en.wikipedia.org/wiki/Dynamic_programming
Newshorts
4
@Akhoy In einer regulären Funktion ja, aber denken Sie an eine rekursive Funktion. Es ruft einen anderen (sich selbst) auf und belässt die Rücksprungadresse des ersteren auf dem Stapel (andernfalls würde der PC wissen, wohin er gehen soll?). Dies ruft sich natürlich jedes Mal erneut auf, wenn eine Rücksprungadresse auf den Stapel geschoben wird. Wenn dies aufgrund eines Basisfalls, der im nächsten Jahrhundert wahrscheinlich nicht erfüllt wird, wegläuft, kommt es zu einem Stapelüberlauf.
Alex
5
Ihr Code führt dasselbe ineffiziente Segment 134217728 Mal aus. Kein Scherz, es ist langsam. Sie sollten bitweise Operatoren verwenden, damit Sie die 9 Ebenen von Schleifen in eine Ebene von Schleifen aufrollen können.
Jack Giffin
82

Dies kann manchmal vorkommen, wenn Sie versehentlich zweimal dieselbe JavaScript-Datei importieren / einbetten. Überprüfen Sie dazu die Registerkarte "Ressourcen" des Inspektors.

lucygenik
quelle
9
Dieses Problem tritt normalerweise auf, wenn Sie versehentlich dieselbe JS-Datei zweimal importieren / einbetten. Über den genauen Prozess, der die rekursive Schleife verursacht, möchte ich nicht spekulieren, aber ich würde annehmen, dass es so etwas wie das Fahren von zwei identischen Autos mit 100 Meilen pro Stunde durch dasselbe Maut-Gateway ist.
lucygenik
3
Ich glaube nicht, dass dies der Fall ist. Wenn zwei gleiche Arten von Funktionen oder Variablen eingebettet sind, überschreibt letztere die vorherigen Definitionen.
Ssudaraka
Ja ... ich weiß nicht wirklich, warum es passiert oder wie der Prozess abläuft, ich hätte es aber auch außer Kraft gesetzt.
lucygenik
Ein bisschen zu spät zur Party, aber ich würde mir vorstellen, dass wenn Code außerhalb einer Funktion liegt, beide innerhalb der beiden JS-Dateien ausgeführt werden und man sich wahrscheinlich nicht überschreibt, da sie sich außerhalb einer Funktion befinden.
Cillian Collins
1
@lucygenik Wenn Sie das nächste Mal vorsichtiger sein möchten, wenn Sie Troll-Änderungen an Ihren Posts genehmigen. Dieser Beitrag wurde fast als Spam gelöscht (Verlauf überprüfen)
Jean-François Fabre
57

In meinem Fall habe ich Eingabeelemente anstelle ihrer Werte gesendet:

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

Anstatt:

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

Dadurch wurde mein Chrome-Tab bis zu einem Punkt eingefroren, an dem nicht einmal der Dialog "Warten / Töten" angezeigt wurde, als die Seite nicht mehr reagierte ...

FKasa
quelle
3
Ich frage mich, warum es für einen solchen Fehler keine Ausnahme gibt ... Danke!
Džuris
Vielen Dank, das hat mich gerettet
Eme Hado
Ich wollte dies als mögliche Lösung hinzufügen. Ich habe gerade genau das getan lol
Michael Buchok
31

Irgendwo in Ihrem Code befindet sich eine rekursive Schleife (dh eine Funktion, die sich schließlich immer wieder selbst aufruft, bis der Stapel voll ist).

Andere Browser haben entweder größere Stapel (sodass Sie stattdessen eine Zeitüberschreitung erhalten) oder sie verschlucken den Fehler aus irgendeinem Grund (möglicherweise ein schlecht platzierter Try-Catch).

Verwenden Sie den Debugger, um den Aufrufstapel zu überprüfen, wenn der Fehler auftritt.

Aaron Digulla
quelle
Vielen Dank für Ihre Antwort. Unter IE / FF scheint der Code einwandfrei zu laufen. Nur in Desktop Safari und iPad Safari wird der Fehler angezeigt. Eigentlich ist die JS-Datei nicht meine eigene Erstellung, sondern eine Bibliotheksdatei (von DWR engine.js). Directwebremoting.org Wie mache ich das mit dem Safari Inspector, auch wenn Sie "Debugger zum Überprüfen des Aufrufstapels" sagen?
Testndtv
Ich habe keine Erfahrung mit Safari Inspector. Versuchen Sie, den JavaScript-Debugger zu öffnen und Ihre Seite zu laden. Der Debugger sollte anhalten, wenn ein nicht abgefangener Fehler ausgegeben wird. Wenn das nicht funktioniert, fragen Sie bei Superuser oder Webmaster (siehe unten auf der Seite)
Aaron Digulla
hatte 2 Funktionen mit dem gleichen Namen !! DOH!
jharris8567
16

Das Problem beim Erkennen von Stapelüberläufen besteht darin, dass sich die Stapelverfolgung manchmal abwickelt und Sie nicht sehen können, was tatsächlich vor sich geht.

Ich habe einige der neueren Debugging-Tools von Chrome dafür nützlich gefunden.

Klicken Sie auf Performance tab, stellen Sie sicher, dass Javascript samplesaktiviert ist, und Sie erhalten so etwas.

Es ist ziemlich offensichtlich, wo der Überlauf hier ist! Wenn Sie auf klicken extendObject, wird die genaue Zeilennummer im Code angezeigt.

Geben Sie hier die Bildbeschreibung ein

Sie können auch Timings sehen, die hilfreich sein können oder nicht, oder einen roten Hering.

Geben Sie hier die Bildbeschreibung ein


Ein weiterer nützlicher Trick, wenn Sie das Problem nicht finden können, besteht darin, viele console.logAussagen dort zu platzieren, wo Sie glauben, dass das Problem liegt. Der vorherige Schritt oben kann Ihnen dabei helfen.

Wenn Sie in Chrome wiederholt identische Daten ausgeben, werden diese wie folgt angezeigt, um zu zeigen, wo das Problem deutlicher liegt. In diesem Fall traf der Stapel 7152 Frames, bevor er schließlich abstürzte:

Geben Sie hier die Bildbeschreibung ein

Simon_Weaver
quelle
13

In meinem Fall habe ich ein großes Byte-Array wie folgt in einen String konvertiert:

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

bytes enthielt mehrere Millionen Einträge, was zu groß ist, um auf den Stapel zu passen.

Nate Glenn
quelle
Ich hatte auch das gleiche Problem mit der gleichen Leitung !! Danke
ksh
Was ist die beste Lösung für die Konvertierung eines großen Byte-Arrays?
ksh
6
@KarthikHande Sie müssen dies in einer for-Schleife anstatt in einem Aufruf tun. var uintArray = new Uint16Array(bytes); var converted = []; uintArray.forEach(function(byte) {converted.push(String.fromCharCode(byte))});
Nate Glenn
Wie konvertiere ich das in JSON? Ich habe JSON.parse ausprobiert, aber es hat nicht funktioniert ... Ich verwende Uintl8Array
ksh
@KarthikHande Ich kann es nicht sagen, ohne das ganze Problem zu sehen. Bitte öffnen Sie eine weitere Frage mit allen Details.
Nate Glenn
6

In meinem Fall wurde das Klickereignis auf das untergeordnete Element übertragen. Also musste ich folgendes sagen:

e.stopPropagation ()

On-Click-Ereignis:

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

Hier ist der HTML-Code:

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

Überprüfen Sie die Fehlerdetails in der Chrome Dev-Symbolleistenkonsole. Dadurch erhalten Sie die Funktionen im Aufrufstapel und werden zu der Rekursion geführt, die den Fehler verursacht.

chim
quelle
3

Fast jede Antwort hier besagt, dass dies nur durch eine Endlosschleife verursacht werden kann. Das ist nicht wahr, Sie könnten den Stapel sonst durch tief verschachtelte Aufrufe überlaufen lassen (um nicht zu sagen, dass dies effizient ist, aber es liegt sicherlich im Bereich des Möglichen). Wenn Sie die Kontrolle über Ihre JavaScript-VM haben, können Sie die Stapelgröße anpassen. Zum Beispiel:

node --stack-size=2000

Siehe auch: Wie kann ich die maximale Größe des Aufrufstapels in Node.js erhöhen?

Ghayes
quelle
2

In meinem Fall wurden zwei jQuery-Modale übereinander gestapelt angezeigt. Das zu verhindern löste mein Problem.

Barry Guvenkaya
quelle
2

Wir haben kürzlich ein Feld zu einer Admin-Site hinzugefügt, an der wir arbeiten - contact_type ... einfach, oder? Wenn Sie den ausgewählten "Typ" aufrufen und versuchen, ihn über einen Ajquery-Ajax-Aufruf zu senden, schlägt dies mit diesem Fehler fehl, der tief in jquery.js vergraben ist. Tun Sie dies nicht:

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

Das Problem ist der Typ: Typ - ich glaube, wir nennen das Argument "Typ" - eine Wertvariable namens Typ zu haben, ist nicht das Problem. Wir haben dies geändert in:

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

Und schrieb some_function.php entsprechend um - Problem gelöst.

Scott
quelle
1

Überprüfen Sie, ob Sie eine Funktion haben, die sich selbst aufruft. Zum Beispiel

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

Dies kann auch einen Maximum call stack size exceededFehler verursachen:

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

Hier gilt das gleiche:

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

Aus den Mozilla Docs :

Beachten Sie jedoch, dass Sie bei der Verwendung von apply auf diese Weise das Risiko eingehen, die Argumentlängenbeschränkung der JavaScript-Engine zu überschreiten. Die Konsequenzen der Anwendung einer Funktion mit zu vielen Argumenten (denken Sie an mehr als Zehntausende von Argumenten) variieren je nach Engine (JavaScriptCore hat ein hartcodiertes Argumentlimit von 65536), da das Limit (in der Tat sogar die Art eines übermäßig großen Stapels) Verhalten) ist nicht spezifiziert. Einige Motoren lösen eine Ausnahme aus. Noch schädlicher ist, dass andere die Anzahl der Argumente, die tatsächlich an die angewendete Funktion übergeben werden, willkürlich begrenzen. Um diesen letzteren Fall zu veranschaulichen: Wenn eine solche Engine eine Grenze von vier Argumenten hätte (die tatsächlichen Grenzen sind natürlich erheblich höher), wäre es so, als ob die Argumente 5, 6, 2, 3 für die obigen Beispiele übergeben worden wären. eher als das gesamte Array.

Also versuche:

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

Beide Aufrufe des identischen Codes unten, wenn sie um 1 verringert wurden, funktionieren in Chrome 32 auf meinem Computer, z. B. 17905 gegenüber 17904. Wenn sie so ausgeführt werden, wird der Fehler "RangeError: Maximale Aufrufstapelgröße überschritten" angezeigt. Es scheint, dass diese Grenze nicht fest codiert ist, sondern von der Hardware Ihres Computers abhängt. Es scheint, dass beim Aufrufen als Funktion diese selbst auferlegte Grenze höher ist als beim Aufrufen als Methode, dh dieser bestimmte Code benötigt weniger Speicher, wenn er als Funktion aufgerufen wird.

Als Methode aufgerufen:

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

ninja.chirp(17905);

Wird als Funktion aufgerufen:

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

chirp(20889);
Elijah Lynn
quelle
0

Sie finden Ihre rekursive Funktion im Crome-Browser. Drücken Sie Strg + Umschalt + J und dann die Registerkarte Quelle. Dadurch erhalten Sie einen Code-Kompilierungsfluss und können den Haltepunkt im Code verwenden.

Vishal Patel
quelle
Manchmal kann es jedoch schwierig sein, herauszufinden, woher der Fehler stammt. Wir haben viel JavaScript auf unserer Website.
Mathias Lykkegaard Lorenzen
0

Ich hatte auch ein ähnliches Problem mit den Details beim Hochladen des Logos über das Dropdown-Feld zum Hochladen des Dropdown-Logos

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

Vor der Korrektur war mein Code:

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

Der Fehler in der Konsole:

Geben Sie hier die Bildbeschreibung ein

Ich habe es gelöst, indem ich es onclick="$('#filePhoto').click()"vom div-Tag entfernt habe.

Spacedev
quelle
Wo haben Sie den Klick ()
hinzugefügt
0

Ich hatte das gleiche Problem, das ich behoben habe, indem ich einen Feldnamen entfernt habe, der zweimal bei Ajax verwendet wurde, z

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

Ich weiß, dass dieser Thread alt ist, aber ich denke, es lohnt sich, das Szenario zu erwähnen, in dem ich dieses Problem gefunden habe, damit es anderen helfen kann.

Angenommen, Sie haben folgende verschachtelte Elemente:

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

Sie können die Ereignisse des untergeordneten Elements nicht innerhalb des Ereignisses des übergeordneten Elements bearbeiten, da es sich selbst überträgt und rekursive Aufrufe ausführt, bis die Ausnahme ausgelöst wird.

Dieser Code schlägt also fehl:

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

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

Sie haben zwei Möglichkeiten, um dies zu vermeiden:

Weslley Ramos
quelle
0

Ich hatte diesen Fehler, weil ich zwei JS-Funktionen mit demselben Namen hatte

Eisdrache
quelle
0

Wenn Sie mit Google Maps arbeiten, überprüfen Sie, ob die Daten, die übergeben new google.maps.LatLngwerden, ein geeignetes Format haben. In meinem Fall wurden sie als undefiniert übergeben.

User-8017771
quelle
0

Das Problem in meinem Fall ist, dass Kinder mit demselben Pfad wie die Eltern routen:

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

Also musste ich die Linie der Kinderroute entfernen

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

In meinem Fall erhalte ich diesen Fehler beim Ajax-Aufruf und die Daten, die ich versucht habe, diese Variable zu übergeben, sind nicht definiert. Dies zeigt mir diesen Fehler, beschreibt aber nicht die nicht definierte Variable. Ich habe definiert hinzugefügt, dass die Variable n einen Wert hat.

asifaftab87
quelle
wurde selbst auf ähnliche Weise verbrannt, in meinem Fall, weil ich einen Variablennamen getippt habe ... praktisch dasselbe.
user2366842
0

Ich bin auf dasselbe Problem gestoßen und habe nicht herausgefunden, was falsch ist. Ich habe Babel die Schuld gegeben;)

Code, der in Browsern keine Ausnahme zurückgibt:

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

Problem wurde schlecht erstellt || (oder) Teil als Babel erstellt eine eigene Typprüfung:

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

also entfernen

|| null

machte Babel Transpilation funktioniert.

Raphael
quelle
0

In meinem Fall habe ich versehentlich den gleichen Variablennamen und die Val-Funktion "class_routine_id" zugewiesen.

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

es sollte sein wie:

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

Ich verwende React-Native 0.61.5 zusammen mit ( npm 6.9.0 & Node 10.16.1 )

Während ich neue Bibliotheken in Project installiere, habe ich eine von

(zB npm install @ react-navigation / native --save)

Die maximale Größe des Aufrufstapels hat den Fehler überschritten

dafür versuche ich

sudo npm cache clean --force

(Hinweis: - Der folgende Befehl benötigt normalerweise 1 bis 2 Minuten, abhängig von Ihrer npm-Cache- Größe.)

DevAelius
quelle
-1

Manchmal ist dies aufgrund des Konvertierungsdatentyps passiert. Beispielsweise haben Sie ein Objekt, das Sie als Zeichenfolge betrachtet haben.

socket.id in nodejs, entweder in js client als Beispiel, ist keine Zeichenfolge. Um es als Zeichenfolge zu verwenden, müssen Sie vorher das Wort Zeichenfolge hinzufügen:

String(socket.id);
Hussein Mahyoub
quelle
-1

Ich habe versucht, eine Variable, einen Wert, zuzuweisen, wenn diese Variable nicht deklariert wurde.

Das Deklarieren der Variablen hat meinen Fehler behoben.

Phillip Quinlan
quelle