Come posso ottenere una traccia dello stack JavaScript quando lancio un’eccezione?

Se lancio personalmente un’eccezione JavaScript (ad esempio, throw "AArrggg" ), come posso ottenere la traccia dello stack (in Firebug o in altro modo)? In questo momento ho appena ricevuto il messaggio.

modifica : come molte persone di seguito hanno postato, è ansible ottenere una traccia dello stack per un’eccezione JavaScript, ma voglio ottenere una traccia dello stack per le mie eccezioni. Per esempio:

 function foo() { bar(2); } function bar(n) { if (n < 2) throw "Oh no! 'n' is too small!" bar(n-1); } 

Quando viene chiamato foo , voglio ottenere una traccia stack che includa le chiamate a foo , bar , bar .

Una versione modificata di questo snippet può in qualche modo aiutare:

 function stacktrace() { function st2(f) { return !f ? [] : st2(f.caller).concat([f.toString().split('(')[0].substring(9) + '(' + f.arguments.join(',') + ')']); } return st2(arguments.callee.caller); } 

EDIT 2 (2017):

In tutti i browser moderni puoi semplicemente chiamare: console.trace(); (Riferimento MDN)

MODIFICA 1 (2013):

Una soluzione migliore (e più semplice), come indicato nei commenti sulla domanda originale, è l’uso della proprietà stack di un object Error modo:

 function stackTrace() { var err = new Error(); return err.stack; } 

Questo genererà un output come questo:

 DBX.Utils.stackTrace@http://localhost:49573/assets/js/scripts.js:44 DBX.Console.Debug@http://localhost:49573/assets/js/scripts.js:9 .success@http://localhost:49573/:462 x.Callbacks/c@http://localhost:49573/assets/js/jquery-1.10.2.min.js:4 x.Callbacks/p.fireWith@http://localhost:49573/assets/js/jquery-1.10.2.min.js:4 k@http://localhost:49573/assets/js/jquery-1.10.2.min.js:6 .send/r@http://localhost:49573/assets/js/jquery-1.10.2.min.js:6 

Fornire il nome della funzione chiamante insieme all’URL, alla sua funzione di chiamata e così via.

Nota che chromium / chrome (altri browser che utilizzano V8) e anche Firefox hanno un’interfaccia comoda per ottenere uno stacktrace attraverso una proprietà stack sugli oggetti Error .

 try { // Code throwing an exception } catch(e) { console.log(e.stack); } 

Si applica per le eccezioni di base e per quelle che si butta. (Considerato che usi la class Error, che comunque è una buona pratica).

Vedi i dettagli sulla documentazione V8

In Firefox sembra che non sia necessario lanciare l’eccezione. È sufficiente fare

 e = new Error(); console.log(e.stack); 

Se hai firebug, c’è un’interruzione su tutti gli errori nella scheda dello script. Una volta che lo script ha raggiunto il punto di interruzione, puoi guardare la finestra dello stack di Firebug:

immagine dello schermo

Non penso che ci sia qualcosa di costruito che tu possa usare, ma ho trovato molti esempi di persone che si muovono da sole.

  • Traccia stack javascript fai da te
  • Uno stacktrace Javascript in qualsiasi browser

Una buona (e semplice) soluzione, come indicato nei commenti sulla domanda originale, è quella di utilizzare la proprietà stack di un object Error modo:

 function stackTrace() { var err = new Error(); return err.stack; } 

Questo genererà un output come questo:

 DBX.Utils.stackTrace@http://localhost:49573/assets/js/scripts.js:44 DBX.Console.Debug@http://localhost:49573/assets/js/scripts.js:9 .success@http://localhost:49573/:462 x.Callbacks/c@http://localhost:49573/assets/js/jquery-1.10.2.min.js:4 x.Callbacks/p.fireWith@http://localhost:49573/assets/js/jquery-1.10.2.min.js:4 k@http://localhost:49573/assets/js/jquery-1.10.2.min.js:6 .send/r@http://localhost:49573/assets/js/jquery-1.10.2.min.js:6 

Fornire il nome della funzione chiamante insieme all’URL e al numero di riga, alla sua funzione di chiamata e così via.

Ho una soluzione davvero elaborata e carina che ho ideato per un progetto al quale sto lavorando attualmente e che ho estratto e rielaborato un po ‘per essere generalizzato. Ecco qui:

 (function(context){ // Only global namespace. var Console = { //Settings settings: { debug: { alwaysShowURL: false, enabled: true, showInfo: true }, stackTrace: { enabled: true, collapsed: true, ignoreDebugFuncs: true, spacing: false } } }; // String formatting prototype function. if (!String.prototype.format) { String.prototype.format = function () { var s = this.toString(), args = typeof arguments[0], args = (("string" == args || "number" == args) ? arguments : arguments[0]); if (!arguments.length) return s; for (arg in args) s = s.replace(RegExp("\\{" + arg + "\\}", "gi"), args[arg]); return s; } } // String repeating prototype function. if (!String.prototype.times) { String.prototype.times = function () { var s = this.toString(), tempStr = "", times = arguments[0]; if (!arguments.length) return s; for (var i = 0; i < times; i++) tempStr += s; return tempStr; } } // Commonly used functions Console.debug = function () { if (Console.settings.debug.enabled) { var args = ((typeof arguments !== 'undefined') ? Array.prototype.slice.call(arguments, 0) : []), sUA = navigator.userAgent, currentBrowser = { firefox: /firefox/gi.test(sUA), webkit: /webkit/gi.test(sUA), }, aLines = Console.stackTrace().split("\n"), aCurrentLine, iCurrIndex = ((currentBrowser.webkit) ? 3 : 2), sCssBlack = "color:black;", sCssFormat = "color:{0}; font-weight:bold;", sLines = ""; if (currentBrowser.firefox) aCurrentLine = aLines[iCurrIndex].replace(/(.*):/, "$1@").split("@"); else if (currentBrowser.webkit) aCurrentLine = aLines[iCurrIndex].replace("at ", "").replace(")", "").replace(/( \()/gi, "@").replace(/(.*):(\d*):(\d*)/, "$1@$2@$3").split("@"); // Show info if the setting is true and there's no extra trace (would be kind of pointless). if (Console.settings.debug.showInfo && !Console.settings.stackTrace.enabled) { var sFunc = aCurrentLine[0].trim(), sURL = aCurrentLine[1].trim(), sURL = ((!Console.settings.debug.alwaysShowURL && context.location.href == sURL) ? "this page" : sURL), sLine = aCurrentLine[2].trim(), sCol; if (currentBrowser.webkit) sCol = aCurrentLine[3].trim(); console.info("%cOn line %c{0}%c{1}%c{2}%c of %c{3}%c inside the %c{4}%c function:".format(sLine, ((currentBrowser.webkit) ? ", column " : ""), ((currentBrowser.webkit) ? sCol : ""), sURL, sFunc), sCssBlack, sCssFormat.format("red"), sCssBlack, sCssFormat.format("purple"), sCssBlack, sCssFormat.format("green"), sCssBlack, sCssFormat.format("blue"), sCssBlack); } // If the setting permits, get rid of the two obvious debug functions (Console.debug and Console.stackTrace). if (Console.settings.stackTrace.ignoreDebugFuncs) { // In WebKit (Chrome at least), there's an extra line at the top that says "Error" so adjust for this. if (currentBrowser.webkit) aLines.shift(); aLines.shift(); aLines.shift(); } sLines = aLines.join(((Console.settings.stackTrace.spacing) ? "\n\n" : "\n")).trim(); trace = typeof trace !== 'undefined' ? trace : true; if (typeof console !== "undefined") { for (var arg in args) console.debug(args[arg]); if (Console.settings.stackTrace.enabled) { var sCss = "color:red; font-weight: bold;", sTitle = "%c Stack Trace" + " ".times(70); if (Console.settings.stackTrace.collapsed) console.groupCollapsed(sTitle, sCss); else console.group(sTitle, sCss); console.debug("%c" + sLines, "color: #666666; font-style: italic;"); console.groupEnd(); } } } } Console.stackTrace = function () { var err = new Error(); return err.stack; } context.Console = Console; })(window); 

Scoprilo su GitHub (attualmente v1.2)! Puoi usarlo come Console.debug("Whatever"); e, a seconda delle impostazioni in Console , stamperà l'output e una traccia dello stack (o semplicemente informazioni semplici / niente di più). Ecco un esempio:

Console.js

Assicurati di giocare con le impostazioni nell'object Console ! È ansible aggiungere una spaziatura tra le linee della traccia e distriggersrla completamente. Eccolo con Console.trace impostato su false :

Nessuna traccia

È anche ansible distriggersre il primo bit di informazioni visualizzato (impostare Console.settings.debug.showInfo su false ) o disabilitare completamente il debug (impostare Console.settings.debug.enabled su false ) in modo da non dover commentare nuovamente un'istruzione di debug ! Lasciali entrare e questo non farà nulla.

Puoi accedere alle proprietà stack ( stacktrace in Opera) di un’istanza Error anche se la stacktrace . Il fatto è che devi assicurarti di usare il throw new Error(string) (non dimenticare la nuova invece della throw string di throw string .

Esempio:

 try { 0++; } catch (e) { var myStackTrace = e.stack || e.stacktrace || ""; } 

Un modo per ottenere una traccia di stack reale su Firebug è creare un errore reale come chiamare una funzione non definita:

 function foo(b){ if (typeof b !== 'string'){ // undefined Error type to get the call stack throw new ChuckNorrisError("Chuck Norris catches you."); } } function bar(a){ foo(a); } foo(123); 

O utilizzare console.error() seguito da un’istruzione throw poiché console.error() mostra la traccia dello stack.

Con il browser Chrome, puoi utilizzare il metodo console.trace : https://developer.chrome.com/devtools/docs/console-api#consoletraceobject

Questo darà una traccia dello stack (come una serie di stringhe) per i moderni Chrome, Opera, Firefox e IE10 +

 function getStackTrace () { var stack; try { throw new Error(''); } catch (error) { stack = error.stack || ''; } stack = stack.split('\n').map(function (line) { return line.trim(); }); return stack.splice(stack[0] == 'Error' ? 2 : 1); } 

Uso:

 console.log(getStackTrace().join('\n')); 

Esclude dallo stack la propria chiamata e il titolo “Errore” utilizzato da Chrome e Firefox (ma non da IE).

Non dovrebbe bloccarsi sui browser più vecchi, ma restituire semplicemente l’array vuoto. Se hai bisogno di più soluzioni universali, consulta stacktrace.js . La sua lista di browser supportati è davvero impressionante, ma a mio avviso è molto grande per quel piccolo compito che è destinato a: 37Kb di testo minificato comprese tutte le dipendenze.

Un aggiornamento alla risposta di Eugene: L’object error deve essere lanciato per consentire a IE (versioni specifiche?) Di popolare la proprietà stack . Il seguente dovrebbe funzionare meglio del suo esempio corrente e dovrebbe evitare di tornare undefined quando in IE.

 function stackTrace() { try { var err = new Error(); throw err; } catch (err) { return err.stack; } } 

Nota 1: Questo genere di cose dovrebbe essere fatto solo durante il debug e disabilitato quando è attivo, specialmente se chiamato frequentemente. Nota 2: Questo potrebbe non funzionare in tutti i browser, ma sembra funzionare in FF e IE 11, che si adattano perfettamente alle mie esigenze.

In Google Chrome (versione 19.0 e successive), il semplice lancio di un’eccezione funziona perfettamente. Per esempio:

 /* file: code.js, line numbers shown */ 188: function fa() { 189: console.log('executing fa...'); 190: fb(); 191: } 192: 193: function fb() { 194: console.log('executing fb...'); 195: fc() 196: } 197: 198: function fc() { 199: console.log('executing fc...'); 200: throw 'error in fc...' 201: } 202: 203: fa(); 

mostrerà la traccia dello stack all’output della console del browser:

 executing fa... code.js:189 executing fb... code.js:194 executing fc... cdoe.js:199 /* this is your stack trace */ Uncaught error in fc... code.js:200 fc code.js:200 fb code.js:195 fa code.js:190 (anonymous function) code.js:203 

Spero che questo aiuto.

   

questo script mostrerà l’errore

funzione:

 function print_call_stack(err) { var stack = err.stack; console.error(stack); } 

caso d’uso:

  try{ aaa.bbb;//error throw here } catch (err){ print_call_stack(err); } 

Questo codice polyfill funziona nei browser moderni (2017) (IE11, Opera, Chrome, FireFox, Yandex):

 printStackTrace: function () { var err = new Error(); var stack = err.stack || /*old opera*/ err.stacktrace || ( /*IE11*/ console.trace ? console.trace() : "no stack info"); return stack; } 

Altre risposte:

 function stackTrace() { var err = new Error(); return err.stack; } 

non funziona in IE 11!

Usando arguments.callee.caller – non funziona in modalità rigorosa in nessun browser!

Puoi usare questa libreria http://www.stacktracejs.com/ . È molto buono

Dalla documentazione

Puoi anche passare il tuo errore per ottenere uno stacktrace non disponibile in IE o Safari 5-

   

È più facile ottenere una traccia di stack su Firefox che su IE, ma fondamentalmente ecco cosa vuoi fare:

Avvolgi il pezzo di codice “problematico” in un blocco try / catch:

 try { // some code that doesn't work var t = null; var n = t.not_a_value; } catch(e) { } 

Se esaminerai il contenuto dell’object “error” contiene i seguenti campi:

e.fileName: il file di origine / la pagina in cui il problema proveniva da e.lineNumber: il numero di riga nel file / pagina in cui è emerso il problema e.message: un messaggio semplice che descrive il tipo di errore e.name: il tipo di errore che si è verificato, nell’esempio precedente dovrebbe essere ‘TypeError’ e.stack: contiene la traccia stack che ha causato l’eccezione

Spero che questo ti aiuti.

Un po ‘tardi per la festa, ma, ecco un’altra soluzione, che rileva automaticamente se arguments.callee è disponibile e utilizza il nuovo Error (). Stack se non lo è. Testato in chrome, safari e firefox.

2 varianti: stackFN (n) fornisce il nome della funzione n lontano dal chiamante immediato e stackArray () fornisce un array, stackArray () [0] è il chiamante immediato.

Provalo su http://jsfiddle.net/qcP9y/6/

 // returns the name of the function at caller-N // stackFN() = the immediate caller to stackFN // stackFN(0) = the immediate caller to stackFN // stackFN(1) = the caller to stackFN's caller // stackFN(2) = and so on // eg console.log(stackFN(),JSON.stringify(arguments),"called by",stackFN(1),"returns",retval); function stackFN(n) { var r = n ? n : 0, f = arguments.callee,avail=typeof f === "function", s2,s = avail ? false : new Error().stack; if (s) { var tl=function(x) { s = s.substr(s.indexOf(x) + x.length);}, tr = function (x) {s = s.substr(0, s.indexOf(x) - x.length);}; while (r-- >= 0) { tl(")"); } tl(" at "); tr("("); return s; } else { if (!avail) return null; s = "f = arguments.callee" while (r>=0) { s+=".caller"; r--; } eval(s); return f.toString().split("(")[0].trim().split(" ")[1]; } } // same as stackFN() but returns an array so you can work iterate or whatever. function stackArray() { var res=[],f = arguments.callee,avail=typeof f === "function", s2,s = avail ? false : new Error().stack; if (s) { var tl=function(x) { s = s.substr(s.indexOf(x) + x.length);}, tr = function (x) {s = s.substr(0, s.indexOf(x) - x.length);}; while (s.indexOf(")")>=0) { tl(")"); s2= ""+s; tl(" at "); tr("("); res.push(s); s=""+s2; } } else { if (!avail) return null; s = "f = arguments.callee.caller" eval(s); while (f) { res.push(f.toString().split("(")[0].trim().split(" ")[1]); s+=".caller"; eval(s); } } return res; } function apple_makes_stuff() { var retval = "iPhones"; var stk = stackArray(); console.log("function ",stk[0]+"() was called by",stk[1]+"()"); console.log(stk); console.log(stackFN(),JSON.stringify(arguments),"called by",stackFN(1),"returns",retval); return retval; } function apple_makes (){ return apple_makes_stuff("really nice stuff"); } function apple () { return apple_makes(); } apple(); 

Ho dovuto indagare su una ricorsione senza fine in smartgwt con IE11, quindi per approfondire, avevo bisogno di una traccia di stack. Il problema era che non ero in grado di usare la console di sviluppo, perché la riproduzione era più difficile in quel modo.
Utilizza quanto segue in un metodo javascript:

 try{ null.toString(); } catch(e) { alert(e.stack); } 

Wow – Non vedo una singola persona in 6 anni che suggerisca di controllare prima di vedere se lo stack è disponibile prima di usarlo! La cosa peggiore che puoi fare in un gestore di errori è lanciare un errore a causa di chiamare qualcosa che non esiste.

Come altri hanno già detto, mentre lo stack è per lo più sicuro da usare ora non è supportato in IE9 o versioni precedenti.

Registro i miei errori imprevisti e una traccia di stack è piuttosto essenziale. Per il massimo supporto, prima controllo per vedere se Error.prototype.stack esiste ed è una funzione. Se è così allora è sicuro usare error.stack .

  window.onerror = function (message: string, filename?: string, line?: number, col?: number, error?: Error) { // always wrap error handling in a try catch try { // get the stack trace, and if not supported make our own the best we can var msg = (typeof Error.prototype.stack == 'function') ? error.stack : "NO-STACK " + filename + ' ' + line + ':' + col + ' + message; // log errors here or whatever you're planning on doing alert(msg); } catch (err) { } }; 

Modifica: sembra che, dal momento che lo stack è una proprietà e non un metodo, puoi tranquillamente chiamarlo anche sui browser più vecchi. Sono ancora confuso perché ero abbastanza sicuro che Error.prototype funzionasse per me in precedenza e ora non funziona, quindi non sono sicuro di cosa sta succedendo.

Usando console.error(e.stack) Firefox mostra solo lo stacktrace nei log, Chrome mostra anche il messaggio. Questa può essere una brutta sorpresa se il messaggio contiene informazioni vitali. Registra sempre entrambi.

 function stacktrace(){ return (new Error()).stack.split('\n').reverse().slice(0,-2).reverse().join('\n'); } 

Ecco una risposta che ti offre le massime prestazioni (IE 6+) e la massima compatibilità. Compatibile con IE 6!

  function stacktrace( log_result ) { var trace_result; // IE 6 through 9 compatibility // this is NOT an all-around solution because // the callee property of arguments is depredicated /*@cc_on // theese fancy conditinals make this code only run in IE trace_result = (function st2(fTmp) { // credit to Eugene for this part of the code return !fTmp ? [] : st2(fTmp.caller).concat([fTmp.toString().split('(')[0].substring(9) + '(' + fTmp.arguments.join(',') + ')']); })(arguments.callee.caller); if (log_result) // the ancient way to log to the console Debug.write( trace_result ); return trace_result; @*/ console = console || Console; // just in case if (!(console && console.trace) || !log_result){ // for better performance in IE 10 var STerror=new Error(); var unformated=(STerror.stack || STerror.stacktrace); trace_result = "\u25BC console.trace" + unformated.substring(unformated.indexOf('\n',unformated.indexOf('\n'))); } else { // IE 11+ and everyone else compatibility trace_result = console.trace(); } if (log_result) console.log( trace_result ); return trace_result; } // test code (function testfunc(){ document.write( "
" + stacktrace( false ) + "

" ); })();

Prova

 throw new Error('some error here') 

Questo funziona abbastanza bene per il cromo:

inserisci la descrizione dell'immagine qui