JavaScript-stackoverloopfout

Van tijd tot tijd heb ik geblogd over JavaScript-browserlimieten en hoe ze zich presenteren. Ik begon met het bespreken van de langlopende scriptdialoog en ging toen verder met andere prestatieproblemen. Ik dacht dat ik de meeste irritante en slecht uitgelegde JavaScript-limieten had behandeld, maar de afgelopen week kwam ik er nog een tegen die het bespreken waard is:stackoverflow-fouten.

Ik heb geschreven over hoe te veel recursie kan leiden tot prestatieproblemen. De meeste browsers hebben limieten voor hoeveel recursie is toegestaan ​​voordat het script automatisch wordt geannuleerd. Dit is een limiet die los staat van de limiet die bepaalt of het script lang actief is. En de limiet gaat echt minder over recursieve oproepen, maar over de grootte van de JavaScript-oproepstack.

Het is niet verrassend dat verschillende browsers verschillende call-stackgroottes hebben. Het is ook niet verrassend dat de methode die ze gebruiken om de call-stack te bepalen ook varieert. De verschillende call-stackgroottes die ik zou kunnen meten zijn (geven of nemen, kan 1 of 2 verschillen):

  • Internet Explorer 7:1.789
  • Firefox 3:3.000
  • Chroom 1:21.837
  • Opera 9.62:10.000
  • Safari 3.2:500

Sommigen hebben gezegd, maar ik kan het niet bevestigen, dat de call-stackgrootte van IE en Opera enigszins gebonden is aan de hoeveelheid RAM op het systeem. Alle andere browsers hebben dit standaard ingesteld. Het is ook vermeldenswaard dat WebKit een veel hogere limiet lijkt te hebben en dat Safari een strengere limiet oplegt aan de JavaScript-engine.

Er zijn twee veelvoorkomende scenario's waarin deze limiet kan worden bereikt. De eerste is eenvoudige recursie, zoals:

function recurse(){
    recurse();
}

recurse();

De tweede is een meer slinkse en moeilijker te identificeren kwestie, vooral in grote codebases, waar twee functies elkaar aanroepen, zoals:

function doSomething(){
    doSomethingElse();
}

function doSomethingElse(){
    doSomething();
}

doSomething();

In elk geval zal de browser uw code stoppen en (hopelijk) een bericht over het probleem weergeven:

  • Internet Explorer 7:"Stack overflow op regel x"
  • Firefox 3:"Te veel recursie"
  • Chrome 1:n.v.t.
  • Opera 9.62:"Afbreken (control stack overflow)"
  • Safari 3.2:”RangeError:maximale call-stackgrootte overschreden.”

Chrome is de enige browser die geen bericht weergeeft dat het probleem aangeeft. Als u een van deze foutmeldingen ziet verschijnen, betekent dit dat een van de twee patronen betrokken is en moet worden gewijzigd. Er is meestal een regelnummer en bestandsnaam gekoppeld aan deze fout, dus het is vrij eenvoudig om fouten op te sporen.

Misschien wel het meest interessante deel van stackoverflow-fouten is dat het in sommige browsers echte JavaScript-fouten zijn en daarom kunnen worden opgevangen met een try-catch uitspraak. Het type uitzondering varieert op basis van de browser die wordt gebruikt. In Firefox is het een InternalError , in Safari en Chrome is het een RangeError , en Internet Explorer gooit een generieke Error type (Opera geeft geen fout, het stopt alleen de JavaScript-engine) . Het is dus mogelijk om zoiets als dit te doen:

try {
    recurse();
} catch (ex){
    alert("Too much recursion!");
}

Als ze niet worden vastgehouden, borrelen deze fouten op zoals elke andere fout zou doen (in Firefox komt het terecht in de Firebug-console, Safari/Chrome verschijnt het in de console), behalve in Internet Explorer. IE geeft niet alleen een JavaScript-fout weer, maar geeft ook een lelijk dialoogvenster weer dat eruitziet als een waarschuwing met het stack-overloopbericht.

Nu, alleen omdat het mogelijk is om deze fout in bijna alle browsers te vangen, betekent niet dat je dat zou moeten doen. Er mag geen code in productie komen met zelfs maar de mogelijkheid van een stack-overflow-fout. Dergelijke gevallen duiden op een slecht codeontwerp en moeten opnieuw worden geëvalueerd en/of opnieuw worden ontworpen om deze fout te voorkomen. Beschouw dit bericht als een hulpmiddel bij het oplossen van dit probleem, niet als een licentie om het in de val te laten lopen en te verhullen.