
Ogni spiegazione di questo errore vi dice la stessa cosa vera e inutile: una funzione ha chiamato se stessa troppe volte, quindi aggiungete un caso base.
Lo sapevate. Quello che volete sapere è quale chiamata lo ha iniziato, e questo è l’unico errore in JavaScript il cui stack trace strutturalmente non può dirvelo.
Tutto quello che è misurato qui sotto è stato eseguito in Chrome. I numeri sono quelli di V8; la forma vale in qualunque motore che catturi uno stack nel momento del lancio.
Cosa contiene davvero il trace
Prendete una catena in cui una funzione chiama un’altra, che chiama una terza, che comincia a ricorrere, e catturate l’errore:
function entryPoint() { return level1() }
function level1() { return level2() }
function level2() { return recurse(0) }
function recurse(n) { return recurse(n + 1) }
try { entryPoint() } catch (e) { console.log(e.stack) }
RangeError: Maximum call stack size exceeded, e poi dieci righe, ognuna di esse recurse:
RangeError: Maximum call stack size exceeded
at recurse (<anonymous>:2:145)
at recurse (<anonymous>:2:156)
at recurse (<anonymous>:2:156)
... seven more identical lines
entryPoint non c’è. Non ci sono nemmeno level1 e level2. Il trace nomina dieci volte la
funzione di cui già sapevate, e nient’altro.
Dieci, perché Error.stackTraceLimit vale 10 per impostazione predefinita.
Alzare il limite non aiuta, e questa è la parte che vale la pena sapere
La mossa ovvia è chiedere più frame:
Error.stackTraceLimit = 200;
Fatelo e otterrete 200 righe. Misurato sulla catena qui sopra, tutte e 200 sono recurse, e
entryPoint continua a mancare.
Il motivo sta in da dove viene catturato il trace. Viene preso nel momento del lancio, che è il punto più profondo dello stack, e da lì torna indietro. Il vostro punto di ingresso sta all’altro capo, a migliaia di frame di distanza. Chiedere 200 frame ve ne porta 200 dal capo sbagliato.
Per questo qui fallisce “leggere lo stack trace dal basso verso l’alto”, che è l’istruzione giusta
per quasi ogni altro errore. Il fondo di questo trace è recurse anche lui.
Catturatelo presto, e la finestra è stretta
L’informazione che volete esiste. È solo disponibile finché lo stack è ancora poco profondo.
Catturate quindi un trace dall’interno della funzione che ricorre, a un passaggio iniziale, e buttate via l’errore:
function recurse(n) {
if (n === 2) console.log(new Error("where did this start").stack);
return recurse(n + 1);
}
Sulla catena qui sopra, quel trace finisce così:
at level2 (<anonymous>:4:27)
at level1 (<anonymous>:4:27)
at entryPoint (<anonymous>:3:31)
Che è la risposta. L’intera catena, in ordine, dalla chiamata che l’ha iniziata.
La finestra è larga più o meno quanto il vostro limite di frame, e questo è il tranello.
Catturare a profondità 2 dà il punto di ingresso. Catturare a profondità 20, con il limite ancora
sul suo valore predefinito di 10, non lo dà, perché a quel punto i dieci frame che il trace
conserverà sono tutti andati oltre l’inizio. Le due mosse quindi funzionano insieme e nessuna
funziona da sola: alzate Error.stackTraceLimit e catturate a un passaggio iniziale.
Se non sapete quale funzione stia ricorrendo, l’errore almeno questo ve lo dice. È il nome ripetuto dieci volte.
La versione che arriva in un ticket
Tutto quello che precede presuppone che voi siate alla tastiera mentre succede. Pensate a cosa vi arriva quando succede a qualcun altro.
La pagina si è congelata, o è diventata bianca, o un pulsante ha smesso di rispondere. Se quella persona ha aperto la console e l’ha fotografata, voi avete dieci righe identiche con il nome di una funzione. Quell’immagine non contiene nessuna informazione su quale percorso di codice sia stato eseguito, che è l’unica cosa di cui avete bisogno.
Questo rende lo stack overflow un caso insolito fra gli errori del browser. Per la maggior parte dei guasti la console è l’artefatto da chiedere, e per questo è quasi priva di valore: dieci copie di un fatto che avreste potuto indovinare. Quello che restringe davvero il campo è la sequenza di azioni immediatamente prima del congelamento, perché il punto di ingresso è una cosa che la persona ha fatto.
Che è un’inversione scomoda. L’errore con più output in console è l’errore in cui l’output in console aiuta meno, e in cui quello che la persona stava facendo conta di più.
Session Replay
Estensione Chrome gratuita. Un clic sulla pagina che non si comporta come dovrebbe acquisisce lo screenshot, la console e il network log, e restituisce un link da incollare nel ticket.
Cosa portarsi via
L’errore è onesto e quasi privo di contenuto: qualcosa ha ricorso senza fermarsi. Nomina la funzione in fondo al ciclo e tace quella in cima, non per avarizia, ma per il punto da cui viene preso uno stack trace.
Quindi smettete di leggere quel trace e andate a prenderne un altro, da un passaggio iniziale, con il limite alzato. Oppure, quando è il browser di qualcun altro, smettete di chiedere la console e chiedete cosa ha premuto.