抛出异常时如何获取 JavaScript 堆栈跟踪?
Posted
技术标签:
【中文标题】抛出异常时如何获取 JavaScript 堆栈跟踪?【英文标题】:How can I get a JavaScript stack trace when I throw an exception? 【发布时间】:2010-10-10 03:54:39 【问题描述】:如果我自己抛出一个 javascript 异常(例如,throw "AArrggg"
),我如何获得堆栈跟踪(在 Firebug 中或其他方式中)?现在我刚刚收到消息。
编辑:正如下面许多人发布的那样,可以获取 JavaScript 异常 的堆栈跟踪,但我想获取 的堆栈跟踪我的 例外。例如:
function foo()
bar(2);
function bar(n)
if (n < 2)
throw "Oh no! 'n' is too small!"
bar(n-1);
当foo
被调用时,我想获得一个堆栈跟踪,其中包括对foo
、bar
、bar
的调用。
【问题讨论】:
Javascript exception stack trace 的可能重复项 自 2008 年以来,Bug 仍然在 Firebug 错误跟踪器上打开:code.google.com/p/fbug/issues/detail?id=1260 - 给它加星标! 答案应该是“throw new Error('arrrgh');”看到这个写得很好的页面:devthought.com/2011/12/22/a-string-is-not-an-error (2013) 您现在可以在 Firefox 上的 Firebug 中获取堆栈跟踪,即使它只是throw 'arrrgh';
,它们看起来与 throw new Error('arrrgh');
相同。然而,Chrome 调试器仍然需要throw new Error('arrrgh');
,但是(但 Chrome 似乎提供了更详细的跟踪)。
我建议更改标题以引用不是源自 Error
的 custom 异常,因为这似乎是这个问题的主题。
【参考方案1】:
我不认为有任何内置的东西可以使用,但是我确实找到了很多人自己滚动的例子。
DIY javascript stack trace A Javascript stacktrace in any browser【讨论】:
啊,谢谢——那里的第一个链接似乎可以做到(尽管缺乏递归支持可能使其无法使用)。 是的,乍一看,我没有看到任何支持递归的东西。我很想知道是否有一个好的解决方案。 我认为第二个链接应该支持 Firefox 和 Opera 的递归,因为它使用错误堆栈跟踪而不是使用 arguments 变量手动构建一个。我很想听听您是否找到递归问题的跨浏览器解决方案(第一篇文章是我的)。 :) Helephant:第二个在这里不起作用,因为当我捕捉到异常时,它是一个“字符串”(即,没有“e.stack”): foo = function() throw "Arg "; 尝试 foo(); catch (e) /* typeof e == "string" */ 也许我错了? (开始强制性地抱怨 Javascript 教程有多愚蠢......) 尝试抛出一个对象:throw name: 'NameOfException', message: 'He's dead, Jim'
.【参考方案2】:
如果您有 firebug,则脚本选项卡中的所有错误选项都会中断。脚本到达断点后,您可以查看 firebug 的堆栈窗口:
【讨论】:
Hrm,这似乎不起作用。它会阻止我在调试器中处理 Javascript 引发的错误(例如,未定义的变量错误),但是当我抛出自己的异常时,除了“未捕获的异常”消息之外,我什么也得不到。【参考方案3】:在 Firefox 上比在 IE 上更容易获得堆栈跟踪,但基本上这是您想要做的:
将“有问题”的代码段包装在 try/catch 块中:
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 :包含导致异常的堆栈跟踪
希望对你有所帮助。
【讨论】:
错了。他正试图捕捉他的 OWN 异常。如果他抛出“asdfg”,他将得到字符串对象,而不是异常对象。他并没有试图捕捉内置异常。【参考方案4】:编辑 2(2017 年):
在所有现代浏览器中,您只需调用:console.trace();
(MDN Reference)
编辑 1 (2013):
在原始问题的 cmets 中指出的更好(和更简单)的解决方案是使用 stack
对象的 stack
属性,如下所示:
function stackTrace()
var err = new Error();
return err.stack;
这将生成如下输出:
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 年):
this snippet 的修改版本可能会有所帮助:
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);
【讨论】:
我不确定为什么没有更多的投票 - 其他答案对我来说效果不佳。顺便说一句,请确保不要将参数视为数组(在此处更新 sn-p:gist.github.com/965603) 无法在 chrome 中工作,tacktrace(): [异常:TypeError: Object # 查看原始问题的评论:您不需要自定义代码,只需使用“throw new Error('arrrgh')” Error.stack 在 IE 中未定义,仅适用于 chrome 和 Mozilla firefox 请注意,caller
现在已弃用,callee
已从 ES5 严格模式中删除。这就是为什么***.com/questions/103598/…【参考方案5】:
您可以访问Error
实例的stack
(Opera 中的stacktrace
)属性,即使您将其扔掉也是如此。问题是,您需要确保使用 throw new Error(string)
(不要忘记 new 而不是 throw string
。
例子:
try
0++;
catch (e)
var myStackTrace = e.stack || e.stacktrace || "";
【讨论】:
stacktrace 在 Opera 中不起作用。我什至找不到关于它的东西。 @NV:stacktrace 似乎不在用户创建的错误上,所以您应该这样做:尝试 0++ catch(e) myStackTrace=e.stack || e.stacktrace 【参考方案6】:请注意,chromium/chrome(其他使用 V8 的浏览器)和 Firefox 确实有一个方便的接口,可以通过 Error 对象上的 stack 属性获取堆栈跟踪。
try
// Code throwing an exception
catch(e)
console.log(e.stack);
它适用于基本异常以及您自己抛出的异常。 (考虑到您使用 Error 类,这无论如何都是一个好习惯)。
查看V8 documentation的详细信息
【讨论】:
Firefox 也支持.stack
属性。
你也可以使用console.error(e.stack);
,所以它看起来像一个默认的异常消息
这个问题专门询问不从Error
派生的异常,因此没有stack
属性。【参考方案7】:
在 Firebug 上获取真正的堆栈跟踪的一种方法是创建一个真正的错误,例如调用未定义的函数:
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);
或者使用console.error()
后跟throw
语句,因为console.error()
显示堆栈跟踪。
【讨论】:
【参考方案8】:在 Google Chrome(版本 19.0 及更高版本)中,只需抛出异常即可完美运行。例如:
/* 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();
将在浏览器的控制台输出中显示堆栈跟踪:
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
希望对您有所帮助。
【讨论】:
【参考方案9】:在 Firefox 中,您似乎不需要抛出异常。做就够了
e = new Error();
console.log(e.stack);
【讨论】:
也适用于移动应用程序(使用 JQM 构建)。 也可以在 Chromium 中使用(无论如何都是版本 43)。 在 Firefox 59 中,当通过window.onerror
调用时,这不起作用,它显示一个几乎为空的堆栈,只有 onerror
函数。
更好的是,你可以这样做:console.log(new Error().stack)
>:( >:( >:(
这将在创建Error
对象的位置记录堆栈,而不是在引发原始异常的位置。【参考方案10】:
在原始问题的 cmets 中指出的一个好的(和简单的)解决方案是使用 Error
对象的 stack
属性,如下所示:
function stackTrace()
var err = new Error();
return err.stack;
这将生成如下输出:
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 和行号、调用函数等。
我已经为我目前正在从事的项目设计了一个非常精细且漂亮的解决方案,并且我已经对其进行了提取和修改以进行概括。这里是:
(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 %c0%c1%c2%c of %c3%c inside the %c4%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);
查看GitHub(当前为 v1.2)!你可以像Console.debug("Whatever");
一样使用它,它会根据Console
中的设置打印输出和堆栈跟踪(或者只是简单的信息/根本没有额外的东西)。这是一个例子:
确保使用Console
对象中的设置!您可以在跟踪线之间添加间距并将其完全关闭。这里将Console.trace
设置为false
:
您甚至可以关闭显示的第一位信息(将Console.settings.debug.showInfo
设置为false
)或完全禁用调试(将Console.settings.debug.enabled
设置为false
),这样您就不必再注释掉调试语句了!把它们留在里面,这将无济于事。
【讨论】:
【参考方案11】:使用Chrome浏览器,可以使用console.trace
方法:https://developer.chrome.com/devtools/docs/console-api#consoletraceobject
【讨论】:
这也适用于 Firefox。 developer.mozilla.org/en-US/docs/Web/API/console/trace【参考方案12】:有点晚了,但是,这是另一个解决方案,如果 arguments.callee 可用,则 自动检测,如果不可用,则使用 new Error().stack。 在 chrome、safari 和 firefox 中测试。
2 个变体 - stackFN(n) 为您提供远离直接调用者的函数 n 的名称,而 stackArray() 为您提供一个数组,stackArray()[0] 是直接调用者。
在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();
【讨论】:
【参考方案13】:我不得不使用 IE11 调查 smartgwt 中的无限递归,因此为了更深入地调查,我需要堆栈跟踪。问题是,我无法使用开发控制台,因为那样复制更加困难。 在 javascript 方法中使用以下内容:
try null.toString(); catch(e) alert(e.stack);
【讨论】:
alert((new Error()).stack);【参考方案14】:你可以使用这个库 http://www.stacktracejs.com/ 。很不错
来自文档
你也可以传入你自己的错误来获取堆栈跟踪不可用 在 IE 或 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>
【讨论】:
链接源https://rawgithub.com/stacktracejs/stacktrace.js/master/stacktrace.js
是旧版本,最新稳定版(匹配code-sn-p)在这里:https://raw.githubusercontent.com/stacktracejs/stacktrace.js/stable/stacktrace.js
【参考方案15】:
这将为现代 Chrome、Opera、Firefox 和 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);
用法:
console.log(getStackTrace().join('\n'));
它从堆栈中排除了它自己的调用以及 Chrome 和 Firefox(但不是 IE)使用的标题“错误”。
它不应该在旧浏览器上崩溃,而只是返回空数组。如果您需要更通用的解决方案,请查看stacktrace.js。它支持的浏览器列表确实令人印象深刻,但在我看来,它对于它的小任务来说非常大:37Kb 的缩小文本,包括所有依赖项。
【讨论】:
【参考方案16】:Eugene 回答的更新:必须抛出错误对象,以便 IE(特定版本?)填充 stack
属性。以下应该比他当前的示例更好,并且应该避免在 IE 中返回 undefined
。
function stackTrace()
try
var err = new Error();
throw err;
catch (err)
return err.stack;
注意 1:这种事情应该只在调试时进行,在运行时禁用,尤其是在频繁调用的情况下。注意 2:这可能不适用于所有浏览器,但似乎适用于 FF 和 IE 11,非常适合我的需求。
【讨论】:
【参考方案17】:哇 - 我在 6 年内没有看到一个人建议我们在使用之前先检查stack
是否可用!在错误处理程序中你能做的最糟糕的事情就是因为调用了不存在的东西而引发错误。
正如其他人所说,虽然stack
现在可以安全使用,但它在 IE9 或更早版本中不受支持。
我记录了我的意外错误,堆栈跟踪非常重要。为了获得最大的支持,我首先检查Error.prototype.stack
是否存在并且是一个函数。如果是这样,那么使用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)
;
编辑:看来,由于stack
是一个属性而不是一个方法,因此即使在旧版浏览器上也可以安全地调用它。我仍然很困惑,因为我很确定以前检查 Error.prototype
对我有用,但现在却没有——所以我不确定发生了什么。
【讨论】:
【参考方案18】:<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>
此脚本将显示错误
【讨论】:
【参考方案19】:使用console.error(e.stack)
Firefox 只在日志中显示堆栈跟踪,
Chrome 也会显示该消息。
如果消息包含重要信息,这可能是一个糟糕的惊喜。始终记录两者。
【讨论】:
【参考方案20】:功能:
function print_call_stack(err)
var stack = err.stack;
console.error(stack);
用例:
try
aaa.bbb;//error throw here
catch (err)
print_call_stack(err);
【讨论】:
【参考方案21】:function stacktrace()
return (new Error()).stack.split('\n').reverse().slice(0,-2).reverse().join('\n');
【讨论】:
虽然此代码可能会回答问题,但提供有关它如何和/或为什么解决问题的额外上下文将提高答案的长期价值。【参考方案22】:这是一个为您提供最大性能(IE 6+)和最大兼容性的答案。兼容 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>" );
)();
【讨论】:
【参考方案23】:试试吧
throw new Error('some error here')
这对 chrome 来说效果很好:
【讨论】:
【参考方案24】:此 polyfill 代码适用于现代 (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;
其他答案:
function stackTrace()
var err = new Error();
return err.stack;
在 IE 11 中不工作!
使用 arguments.callee.caller - 在任何浏览器中都不能在严格模式下工作!
【讨论】:
【参考方案25】:至少在 Edge 2021 中:
console.groupCollapsed('jjjjjjjjjjjjjjjjj')
console.trace()
try
throw "kuku"
catch(e)
console.log(e.stack)
console.groupEnd()
traceUntillMe()
你已经完成了我的朋友
【讨论】:
以上是关于抛出异常时如何获取 JavaScript 堆栈跟踪?的主要内容,如果未能解决你的问题,请参考以下文章