Si je jette moi-même une exception JavaScript (par exemple, throw "AArrggg"
), comment puis-je obtenir la trace de la pile (dans Firebug ou autrement)? En ce moment je viens de recevoir le message.
edit: Comme beaucoup de personnes ci-dessous ont posté, il est possible d’obtenir une trace de pile pour une exception JavaScript mais je souhaite obtenir une trace de pile pour mes exceptions. Par exemple:
function foo() {
bar(2);
}
function bar(n) {
if (n < 2)
throw "Oh no! 'n' is too small!"
bar(n-1);
}
Lorsque foo
est appelé, je souhaite obtenir une trace de pile comprenant les appels à foo
, bar
, bar
.
Éditer 2 (2017):
Dans tous les navigateurs modernes, vous pouvez simplement appeler: console.trace();
(Référence MDN)
Éditer 1 (2013):
Une solution meilleure (et plus simple) comme indiqué dans les commentaires sur la question initiale consiste à utiliser la propriété stack
d'un objet Error
comme suit:
function stackTrace() {
var err = new Error();
return err.stack;
}
Cela générera une sortie comme ceci:
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
Donner le nom de la fonction appelante avec l'URL, sa fonction appelante, etc.
Original (2009):
Une version modifiée de cet extrait peut aider quelque peu:
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);
}
Notez que chrome/chrome (autres navigateurs utilisant V8) et Firefox ont une interface pratique pour obtenir une trace de pile via une propriété stack sur Erreur objets.
try {
// Code throwing an exception
} catch(e) {
console.log(e.stack);
}
Cela s'applique aussi bien aux exceptions de base que pour celles que vous lancez. (Considéré que vous utilisez la classe Error, ce qui est quand même une bonne pratique).
Voir les détails sur documentation V8
Dans Firefox, il semble que vous n’ayez pas besoin de lancer l’exception. Il suffit de faire
e = new Error();
console.log(e.stack);
Si vous avez firebug, il y a une option de rupture de toutes les erreurs dans l'onglet de script. Une fois que le script a atteint votre point d'arrêt, vous pouvez regarder la fenêtre de pile de firebug:
Une bonne (et simple) solution, comme indiqué dans les commentaires sur la question initiale, consiste à utiliser la propriété stack
d'un objet Error
de la manière suivante:
function stackTrace() {
var err = new Error();
return err.stack;
}
Cela générera une sortie comme ceci:
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
Donner le nom de la fonction appelante avec l'URL et le numéro de ligne, sa fonction appelante, etc.
J'ai une solution très élaborée et jolie que j'ai conçue pour un projet sur lequel je travaille actuellement et que j'ai extraite et retravaillée un peu pour la généraliser. C'est ici:
(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);
Découvrez-le sur GitHub (actuellement v1.2)! Vous pouvez l’utiliser comme Console.debug("Whatever");
et, selon les réglages de Console
, il imprimera le résultat et une trace de pile (ou simplement de simples informations/rien d’extraordinaire). Voici un exemple:
Assurez-vous de jouer avec les réglages dans l'objet Console
! Vous pouvez ajouter un espacement entre les lignes du tracé et le désactiver complètement. Le voici avec Console.trace
réglé sur false
:
Vous pouvez même désactiver le premier bit d’information affiché (définir Console.settings.debug.showInfo
sur false
) ou désactiver complètement le débogage (définir Console.settings.debug.enabled
sur false
) afin de ne jamais avoir à commenter. une déclaration de débogage à nouveau! Il suffit de les laisser et cela ne fera rien.
Je ne pense pas que vous puissiez utiliser quoi que ce soit d'autre, mais j'ai trouvé beaucoup d'exemples de personnes qui se sont lancées.
Vous pouvez accéder aux propriétés stack
(stacktrace
dans Opera) d'une instance Error
même si vous l'avez lancée. Le fait est que vous devez vous assurer que vous utilisez throw new Error(string)
(n'oubliez pas le nouvea au lieu de throw string
.
Exemple:
try {
0++;
} catch (e) {
var myStackTrace = e.stack || e.stacktrace || "";
}
Avec le navigateur Chrome, vous pouvez utiliser la méthode console.trace
: https://developer.chrome.com/devtools/docs/console-api#consoletraceobject
Mise à jour de la réponse d'Eugene: l'objet erreur doit être lancé pour que IE (versions spécifiques?) Remplisse la propriété stack
. Ce qui suit devrait fonctionner mieux que son exemple actuel et éviter de renvoyer undefined
dans IE.
function stackTrace() {
try {
var err = new Error();
throw err;
} catch (err) {
return err.stack;
}
}
Note 1: Ce genre de chose ne devrait être fait que lors du débogage et désactivé en direct, en particulier s'il est appelé fréquemment. Note 2: Cela peut ne pas fonctionner dans tous les navigateurs, mais semble fonctionner en FF et IE 11, ce qui convient parfaitement à mes besoins.
une façon d'obtenir une trace de pile réelle sur Firebug est de créer une erreur réelle, comme appeler une fonction non définie:
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);
Ou utilisez console.error()
suivi d'une instruction throw
puisque console.error()
affiche la trace de la pile.
Cela donnera une trace de pile (sous forme de tableau de chaînes) pour Chrome, Opera, Firefox et IE10 + modernes.
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);
}
Usage:
console.log(getStackTrace().join('\n'));
Il exclut de la pile son propre appel ainsi que le titre "Erreur" utilisé par Chrome et Firefox (mais pas par IE).
Il ne devrait pas planter sur les anciens navigateurs, mais simplement renvoyer un tableau vide. Si vous avez besoin d'une solution plus universelle, regardez stacktrace.js . Sa liste de navigateurs pris en charge est vraiment impressionnante, mais à mon sens, elle est très volumineuse pour cette petite tâche à laquelle elle est destinée: 37 Ko de texte minifié, y compris toutes les dépendances.
Dans Google Chrome (version 19.0 et les versions ultérieures), le simple lancement d'une exception fonctionne parfaitement. Par exemple:
/* 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();
affichera la trace de la pile à la sortie de la console du navigateur:
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
J'espère que cette aide.
une fonction:
function print_call_stack(err) {
var stack = err.stack;
console.error(stack);
}
cas d'utilisation:
try{
aaa.bbb;//error throw here
}
catch (err){
print_call_stack(err);
}
<script type="text/javascript"
src="https://rawgithub.com/stacktracejs/stacktrace.js/master/stacktrace.js"></script>
<script type="text/javascript">
try {
// error producing code
} catch(e) {
var trace = printStackTrace({e: e});
alert('Error!\n' + 'Message: ' + e.message + '\nStack trace:\n' + trace.join('\n'));
// do something else with error
}
</script>
ce script montrera l'erreur
Ce code polyfill fonctionnant dans les navigateurs modernes (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;
}
Autres réponses:
function stackTrace() {
var err = new Error();
return err.stack;
}
ne fonctionne pas dans IE 11!
Utilisation de arguments.callee.caller - ne fonctionne pas en mode strict dans aucun navigateur!
Un peu en retard pour le parti, mais voici une autre solution, qui détecte automatiquement si arguments.callee est disponible, et utilise la nouvelle erreur (). Stack si ne pas. Testé en chrome, safari et firefox.
2 variantes - stackFN (n) vous donne le nom de la fonction n loin de l'appelant immédiat, et stackArray () vous donne un tableau, stackArray () [0] étant l'appelant immédiat.
Essayez-le à 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();
Vous pouvez utiliser cette bibliothèque http://www.stacktracejs.com/ . C'est très bien
De la documentation
Vous pouvez également transmettre votre propre erreur pour obtenir un stacktrace non disponible dans IE ou Safari 5-
<script type="text/javascript" src="https://rawgithub.com/stacktracejs/stacktrace.js/master/stacktrace.js"></script>
<script type="text/javascript">
try {
// error producing code
} catch(e) {
var trace = printStackTrace({e: e});
alert('Error!\n' + 'Message: ' + e.message + '\nStack trace:\n' + trace.join('\n'));
// do something else with error
}
</script>
Voici une réponse qui vous donne les performances maximales (IE 6+) et la compatibilité maximale. Compatible avec 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( "<pre>" + stacktrace( false ) + "</pre>" );
})();
function stacktrace(){
return (new Error()).stack.split('\n').reverse().slice(0,-2).reverse().join('\n');
}
Je devais étudier une récursion sans fin dans smartgwt avec IE11, donc pour approfondir, il me fallait une trace de pile. Le problème était que je ne pouvais pas utiliser la console de développement, car la reproduction était plus difficile de cette façon.
Utilisez les éléments suivants dans une méthode javascript:
try{ null.toString(); } catch(e) { alert(e.stack); }
Il est plus facile d’obtenir une trace de pile sur Firefox que sur IE, mais voici ce que vous voulez faire:
Enveloppez le morceau de code "problématique" dans un bloc try/catch:
try {
// some code that doesn't work
var t = null;
var n = t.not_a_value;
}
catch(e) {
}
Si vous voulez examiner le contenu de l'objet "error", il contient les champs suivants:
e.fileName: fichier/page source d'où provient le problème e.lineNumber: numéro de la ligne dans le fichier/page où le problème est survenu e.message: un simple message décrivant le type d'erreur survenu. e.name: type d'erreur ci-dessus, il doit s'agir de 'TypeError' e.stack: contient la trace de pile qui a provoqué l'exception
J'espère que cela vous aide.
Wow - Je ne vois pas une seule personne sur 6 ans suggérer de vérifier d'abord si stack
est disponible avant de l'utiliser! La pire chose à faire dans un gestionnaire d'erreurs est de lancer une erreur car elle appelle quelque chose qui n'existe pas.
Comme d'autres l'ont dit, bien que stack
puisse être utilisé en toute sécurité, il n'est plus pris en charge par IE9 ou une version antérieure.
Je me connecte mes erreurs inattendues et une trace de la pile est assez essentielle. Pour un soutien maximal, je vérifie d’abord si Error.prototype.stack
existe et est une fonction. Si c'est le cas, il est prudent d'utiliser 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)
{
}
};
Edit: Il apparaît que, puisque stack
est une propriété et non une méthode, vous pouvez l'appeler en toute sécurité même sur des navigateurs plus anciens. Je suis toujours perplexe, car j’étais à peu près sûr de vérifier Error.prototype
a déjà fonctionné pour moi auparavant, mais c’est maintenant le cas - je ne suis donc pas sûr de ce qui se passe.
Utilisation de console.error(e.stack)
Firefox ne montre que la trace de pile dans les journaux, Chrome affiche également le message. Cela peut être une mauvaise surprise si le message contient des informations vitales. Toujours connecter les deux.