引发异常时如何获取JavaScript堆栈跟踪?


518

如果我自己抛出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被调用时,我希望得到一个堆栈跟踪,其中包括在两个电话foobarbar



自2008年以来,错误仍在Firebug错误跟踪器上打开:code.google.com/p/fbug/issues/detail?id=1260-为它加星标!
米勒·梅代罗斯

13
答案应该是“引发新的Error('arrrgh');”。看到写得很好的页面:devthought.com/2011/12/22/a-string-is-not-an-error
优雅的骰子

1
(2013)您现在可以在Firefox上的Firebug中获得堆栈跟踪,即使它很简单throw 'arrrgh';,而且看起来与相同throw new Error('arrrgh');。但是,Chrome调试器仍然需要throw new Error('arrrgh');按照说明进行操作(但Chrome似乎提供了更多详细的跟踪信息)。
user56reinstatemonica8

26
@ChetanSastry我在Google上搜索了“ javascript堆栈跟踪”,这是第一个结果
David Sykes

Answers:


754

编辑2(2017):

在所有现代浏览器中,您都可以简单地调用:console.trace(); (MDN参考)

编辑1(2013):

正如对原始问题的评论中所指出的那样,更好(更简单)的解决方案是使用对象的stack属性,Error如下所示:

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):

此代码段的修改版本可能会有所帮助:

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);
}

11
我不确定为什么没有对此进行更多投票-其他答案对我而言效果不佳。顺便说一句,请确保不要将参数视为数组(此处更新的片段为:gist.github.com/965603
ripper234 2011年

1
在chrome中不起作用,tacktrace():[异常:TypeError:对象#<Object>没有方法
hetaoblog13年

3
看到对原始问题的评论:您不需要自定义代码,只需使用“引发新错误('arrrgh')”
约书亚·理查森

16
Error.stack在IE中是未定义的,仅适用于chrome和Mozilla firefox
Philipp Munin

4
请注意,caller现在已弃用该功能,callee并将其从ES5严格模式中删除。这也是为什么stackoverflow.com/questions/103598/...
PhilT

187

请注意,chrome / chrome(其他使用V8的浏览器)以及Firefox确实具有方便的界面,可通过Error对象上的stack属性获取stacktrace 。

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

它适用于基本异常以及您自己抛出的异常。(考虑使用Error类,这是一个好习惯)。

查看有关V8文档的详细信息


12
Firefox也支持该.stack属性。
kennytm

2
希望我可以投票100次!谢谢Jocelyn。
safrazik

1
您还可以使用console.error(e.stack);它,使其看起来像默认的异常消息
Bruno Peres

80

在Firefox中,似乎不需要引发异常。做就足够了

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

同样适用于移动应用程序(使用JQM构建)。
Samik R

也可以在Chromium中使用(无论如何都是43版)。
安迪·贝弗利

在Firefox 59中,当通过调用时window.onerror,此功能不起作用,它显示了只有onerror函数的几乎为空的堆栈。
Code4R7

更好的是,您可以这样做:console.log(new Error().stack)> : (> :(> :(
Andrew

25

如果您有萤火虫,则脚本选项卡中的所有错误选项都会中断。脚本达到断点后,您可以查看firebug的堆栈窗口:

屏幕截图


5
嗯,那似乎不起作用。它使我无法在调试器中处理Javascript引发的错误(例如,未定义的变量错误),但是当我抛出自己的异常时,除了“ Uncaught exception”消息外,我什么也没有得到。
David Wolever'3

11

正如对原始问题的评论中指出的那样,一个好的(简单)解决方案是使用对象的stack属性,Error如下所示:

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 %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);

GitHub(当前为v1.2)上查看!您可以像使用它一样Console.debug("Whatever");,它将根据中的设置Console打印输出和堆栈跟踪(或只是简单的信息/一点都没有)。这是一个例子:

Console.js

确保使用Console对象中的设置!您可以在迹线的行之间添加间距并将其完全关闭。在这里它Console.trace设置为false

无痕

您甚至可以关闭显示的信息的第一位(设置Console.settings.debug.showInfofalse)或完全禁用调试(设置Console.settings.debug.enabledfalse),因此您无需再次注释掉调试语句!只需将它们留在里面,这将无济于事。


10

我不认为您可以使用任何内置功能,但是我确实找到了很多人在做自己的事情的例子。


嗯,谢谢-那里的第一个链接似乎可行(尽管缺少递归支持可能使其无法使用)。
David Wolever 09年

是的,乍一看我没有发现任何支持递归的方法。我很想知道是否有一个好的解决方案。
Mark Biek 09年

1
我认为第二个链接应该支持Firefox和Opera的递归,因为它使用错误堆栈跟踪,而不是使用arguments变量手动构建一个。我很想听听您是否找到用于递归问题的跨浏览器解决方案(第一篇文章是我的)。:)
Helephant

Helephant:第二个在这里不起作用,因为当我捕获到异常时,它是一个“字符串”(即没有“ e.stack”):foo = function(){throw“ Arg”; }尝试{foo(); } catch(e){/ * typeof e ==“ string” * /}也许我把它弄错了吗?(关于如何愚蠢的Javascript教程,有强制性的
责备

尝试抛出一个对象:throw { name: 'NameOfException', message: 'He's dead, Jim' }
亚伦·迪古拉2011年

7

您可以访问实例的stackstacktrace在Opera中)属性,Error即使您将其扔了也可以。关键是,您需要确保使用throw new Error(string)(不要忘记使用新的而不是throw string

例:

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

stacktrace在Opera中不起作用。我什至找不到任何东西。
NVI

@NV:看来stacktrace不在用户创建的错误上,因此您应该这样做:试试{0 ++} catch(e){myStackTrace = e.stack || e.stacktrace}
Eli Gray


7

这将为现代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的压缩文本,包括所有依赖项。


7

Eugene答案的更新:必须抛出该错误对象,以便IE(特定版本?)填充stack属性。以下内容应比其当前示例更好,并且应避免undefined在IE中返回。

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

注1:这种事情仅应在调试时完成,而在实时运行时应禁用,尤其是在频繁调用时。注意2:可能无法在所有浏览器中使用,但似乎可以在FF和IE 11中使用,正好适合我的需求。


6

在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()显示了堆栈跟踪。


4

此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-在任何浏览器中都不能在严格模式下使用!


3

在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

希望能有所帮助。


3

功能:

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

用例:

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

2
<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>

该脚本将显示错误


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

2
尽管此代码可以回答问题,但提供有关如何和/或为什么解决问题的其他上下文将提高​​答案的长期价值。
唐老鸭

1

有点晚了,但是,这是另一种解决方案,可以自动检测 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();

1

您可以使用此库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是一个旧版本,最新的稳定版本(与代码段匹配)在这里:https://raw.githubusercontent.com/stacktracejs/stacktrace.js/stable/stacktrace.js
Frederic Leitenberger 2014年

1

这是给您最大性能(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>" );
})();


0

在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:包含导致异常的堆栈跟踪

我希望这能够帮到你。


1
错误。他正在尝试捕获自己的OWN异常。如果抛出“ asdfg”,他将得到字符串对象,而不是异常对象。他没有试图捕获内置的异常。
伊万·武恰卡(IvanVučica)2009年

0

我必须使用IE11研究smartgwt中的无限递归,因此为了更深入地研究,我需要堆栈跟踪。问题是,我无法使用开发控制台,因为这种方式的复制更加困难。
在javascript方法中使用以下内容:

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

alert((新的Error())。stack);
Rich remer 2014年

0

哇-我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以前检查对我有用,现在却不起作用-所以我不确定发生了什么。



0

你试一试

throw new Error('some error here')

这对于chrome非常有效:

在此处输入图片说明

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.