Cum pot obține un traseu de stivă JavaScript atunci când arunc o excepție?
Dacă arunc eu însumi o excepție JavaScript (de exemplu, throw "AArrggg"), cum pot obține traseul stivei (în Firebug sau altfel)? În acest moment primesc doar mesajul.
editare: Așa cum au postat multe persoane mai jos, este posibil să obții un traseu al stivei pentru o excepție JavaScript, dar vreau să obțin un traseu al stivei pentru excepțiile mele. De exemplu:
function foo() {
bar(2);
}
function bar(n) {
if (n < 2)
throw "Oh no! 'n' is too small!"
bar(n-1);
}
Când este apelat foo, vreau să obțin o trasare a stivei care să includă apelurile către foo, bar, bar.
Răspuns #1
Editarea 2 (2017):
În toate browserele moderne poți pur și simplu să apelezi: console.trace(); (Referință MDN)
Edit 1 (2013):
O soluție mai bună (și mai simplă), așa cum s-a menționat în comentariile la întrebarea originală, este să folosești proprietatea stack a unui obiect Error astfel:
function stackTrace() {
var err = new Error();
return err.stack;
}
Acest lucru va genera un rezultat precum acesta:
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
Furnizarea numelui funcției apelante împreună cu URL-ul, funcția sa apelantă și așa mai departe.
Original (2009):
O versiune modificată a acestui fragment poate ajuta oarecum:
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);
}
Răspunsul #2
Chrome/Chromium și alte browsere care folosesc V8, precum și Firefox, au o interfață convenabilă pentru a obține un stacktrace prin proprietatea stack a obiectelor Error:
try {
// Code throwing an exception
throw new Error();
} catch(e) {
console.log(e.stack);
}
Vezi detalii în documentația V8
Răspunsul #3
În Firefox se pare că nu este necesar să arunci excepția. Este suficient să faci
e = new Error();
console.log(e.stack);
Răspunsul #4
Dacă ai Firebug, există o opțiune de întrerupere la toate erorile în fila script. Odată ce scriptul a atins punctul tău de întrerupere, poți să te uiți la fereastra de stive a lui Firebug:
Răspunsul #5
O soluție bună (și simplă), așa cum se observă în comentariile la întrebarea originală, este să folosești proprietatea stack a unui obiect Error astfel:
function stackTrace() {
var err = new Error();
return err.stack;
}
Acest lucru va genera un rezultat precum acesta:
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
Furnizând numele funcției apelante împreună cu URL-ul și numărul liniei, funcția care o apelează și așa mai departe.
Am o soluție foarte elaborată și frumoasă pe care am conceput-o pentru un proiect la care lucrez în prezent și am extras-o și lucrat puțin la ea pentru a fi generalizată. Iată aici:
(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);
Verifică-l pe GitHub (în prezent v1.2)! Îl poți folosi astfel: Console.debug("Whatever"); și acesta, în funcție de setările din Console, va afișa rezultatul și un stack trace (sau doar informații simple/nimic în plus). Iată un exemplu:
Asigură-te că te joci cu setările din obiectul Console! Poți adăuga spațiere între liniile de urmărire și îl poți opri complet. Iată-l cu Console.trace setat la false:
Poți chiar să dezactivezi prima parte a informațiilor afișate (setați Console.settings.debug.showInfo pe false) sau să dezactivezi complet depanarea (setați Console.settings.debug.enabled pe false) astfel încât să nu mai trebuiască să comentezi niciodată o instrucțiune de depanare! Pur și simplu lasă-le acolo și acest lucru nu va face nimic.
Răspuns #6
Nu cred că există ceva integrat pe care să îl poți folosi, totuși am găsit multe exemple în care oamenii și-au creat singuri propriile soluții.
- Trasare stivă JavaScript DIY
- Un stacktrace Javascript în orice browser


