How can I get a JavaScript stack trace when I throw an exception?
如果我自己抛出JavaScript异常(例如,
编辑:正如下面的许多人发布的那样,有可能获得JavaScript异常的堆栈跟踪,但我想获得异常的堆栈跟踪。 例如:
1 2 3 4 5 6 7 8 | function foo() { bar(2); } function bar(n) { if (n < 2) throw"Oh no! 'n' is too small!" bar(n-1); } |
当调用
编辑2(2017):
在所有现代浏览器中,您只需调用:
编辑1(2013):
在原始问题的注释中指出的更好(和更简单)的解决方案是使用
1 2 3 4 | function stackTrace() { var err = new Error(); return err.stack; } |
这将生成如下输出:
1 2 3 4 5 6 7 | 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 |
给出调用函数的名称以及URL,调用函数等。
原创(2009年):
此代码段的修改版本可能会有所帮助:
1 2 3 4 5 6 7 | 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); } |
请注意,chrome / chrome(使用V8的其他浏览器)以及Firefox都有一个方便的界面来通过Error对象上的堆栈属性获取堆栈跟踪。
1 2 3 4 5 | try { // Code throwing an exception } catch(e) { console.log(e.stack); } |
它适用于基本异常以及您自己抛出的异常。 (认为??你使用的是Error类,这无论如何都是一种很好的做法)。
查看有关V8文档的详细信息
在Firefox中,您似乎不需要抛出异常。这足够了
1 2 | e = new Error(); console.log(e.stack); |
如果您有firebug,则脚本选项卡中的所有错误选项都会中断。一旦脚本达到你的断点,你可以看看firebug的堆栈窗口:
原始问题的注释中指出的一个好的(简单的)解决方案是使用
1 2 3 4 | function stackTrace() { var err = new Error(); return err.stack; } |
这将生成如下输出:
1 2 3 4 5 6 7 | 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 |
给出调用函数的名称以及URL和行号,调用函数等。
我有一个非常精细和漂亮的解决方案,我为我正在进行的项目设计的,我已经提取并重新设计了一些以便进行概括。这里是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | (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(" "), 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) ?" " :" ")).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); |
在GitHub上查看(目前是v1.2)!您可以像
确保使用
您甚至可以关闭显示的第一位信息(将
我不认为你可以使用任何内置的东西,但我确实找到了很多人自己动手的例子。
- DIY javascript堆栈跟踪
- 任何浏览器中的Javascript堆栈跟踪
使用Chrome浏览器,您可以使用
您可以访问
例:
1 2 3 4 5 | try { 0++; } catch (e) { var myStackTrace = e.stack || e.stacktrace ||""; } |
在Firebug上获得真正的堆栈跟踪的一种方法是创建一个真正的错误,比如调用一个未定义的函数:
1 2 3 4 5 6 7 8 9 10 11 12 | 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); |
或者使用
更新Eugene的答案:必须抛出错误对象,以便IE(特定版本?)填充
1 2 3 4 5 6 7 8 | function stackTrace() { try { var err = new Error(); throw err; } catch (err) { return err.stack; } } |
注1:这种事情只应在调试时完成,并在实时时禁用,特别是在频繁调用时。注意2:这可能不适用于所有浏览器,但似乎适用于FF和IE 11,这很适合我的需要。
这将为现代Chrome,Opera,Firefox和IE10 +提供堆栈跟踪(作为字符串数组)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | function getStackTrace () { var stack; try { throw new Error(''); } catch (error) { stack = error.stack || ''; } stack = stack.split(' ').map(function (line) { return line.trim(); }); return stack.splice(stack[0] == 'Error' ? 2 : 1); } |
用法:
1 2 | console.log(getStackTrace().join(' ')); |
它从堆栈中排除了自己的调用以及Chrome和Firefox(但不是IE)使用的标题"错误"。
它不应该在旧浏览器上崩溃,而只是返回空数组。如果您需要更多通用解决方案,请查看stacktrace.js。它支持的浏览器列表确实令人印象深刻,但在我看来,这对于它的小任务非常重要:37Kb的缩小文本,包括所有依赖项。
在谷歌浏览器(版本19.0及更高版本)中,简单地抛出异常非常有效。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | /* 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(); |
将在浏览器的控制台输出中显示堆栈跟踪:
1 2 3 4 5 6 7 8 9 | 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 |
希望这有帮助。
功能:
1 2 3 4 | function print_call_stack(err) { var stack = err.stack; console.error(stack); } |
用例:
1 2 3 4 5 6 | try{ aaa.bbb;//error throw here } catch (err){ print_call_stack(err); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <script type="text/javascript" src="https://rawgithub.com/stacktracejs/stacktrace.js/master/stacktrace.js"> <script type="text/javascript"> try { // error producing code } catch(e) { var trace = printStackTrace({e: e}); alert('Error! ' + 'Message: ' + e.message + ' Stack trace: ' + trace.join(' ')); // do something else with error } |
此脚本将显示错误
这个polyfill代码在现代(2017)浏览器(IE11,Opera,Chrome,FireFox,Yandex)中工作:
1 2 3 4 5 | printStackTrace: function () { var err = new Error(); var stack = err.stack || /*old opera*/ err.stacktrace || ( /*IE11*/ console.trace ? console.trace() :"no stack info"); return stack; } |
其他答案:
1 2 3 4 | function stackTrace() { var err = new Error(); return err.stack; } |
不在IE 11中工作!
使用arguments.callee.caller - 在任何浏览器中都不能在严格模式下工作!
派对迟到了,但是,这是另一个解决方案,如果arguments.callee可用则自动检测,如果没有则使用新的Error()。stack。
在chrome,safari和firefox中测试过。
2个变体 - stackFN(n)为您提供远离直接调用者的函数n的名称,stackArray()为您提供一个数组,stackArray()[0]作为直接调用者。
在http://jsfiddle.net/qcP9y/6/试试吧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | // 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(); |
您可以使用此库http://www.stacktracejs.com/。这很好
从文档
You can also pass in your own Error to get a stacktrace not available
in IE or Safari 5-
1 2 3 4 5 6 7 8 9 10 11 12 13 | <script type="text/javascript" src="https://rawgithub.com/stacktracejs/stacktrace.js/master/stacktrace.js"> <script type="text/javascript"> try { // error producing code } catch(e) { var trace = printStackTrace({e: e}); alert('Error! ' + 'Message: ' + e.message + ' Stack trace: ' + trace.join(' ')); // do something else with error } |
1 2 3 4 5 | function stacktrace(){ return (new Error()).stack.split(' ').reverse().slice(0,-2).reverse().join(' '); } |
这是一个答案,为您提供最大性能(IE 6+)和最大兼容性。与IE 6兼容!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 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(' ',unformated.indexOf(' '))); } 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("[cc lang="javascript"]" + stacktrace( false ) +" |
");
})(); 代码> PRE>
哇 - 我没有看到一个人在6年内建议我们先检查
正如其他人所说,虽然
我记录我的意外错误,堆栈跟踪非常重要。为获得最大支持,我首先检查
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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) { } }; |
编辑:似乎由于
使用
Chrome也会显示该消息。
如果消息包含重要信息,这可能是一个不好的惊喜。始终记录两者。
在Firefox上获取堆栈跟踪比在IE上更容易,但从根本上说这就是你想要做的事情:
在try / catch块中包装"有问题"的代码片段:
1 2 3 4 5 6 7 | try { // some code that doesn't work var t = null; var n = t.not_a_value; } catch(e) { } |
如果要检查"错误"对象的内容,则它包含以下字段:
e.fileName:问题来源的源文件/页面
e.lineNumber:出现问题的文件/页面中的行号
e.message:描述发生了什么类型错误的简单消息
e.name:发生的错误类型,在上面的示例中应该是'TypeError'
e.stack:包含导致异常的堆栈跟踪
我希望这能够帮到你。
试一试
1 | throw new Error('some error here') |
这适用于chrome:
我不得不用IE11调查smartgwt中的无限递归,所以为了更深入地研究,我需要一个堆栈跟踪。问题是,我无法使用开发控制台,因为复制更加困难。
在javascript方法中使用以下内容:
1 | try{ null.toString(); } catch(e) { alert(e.stack); } |