如果我自己抛出一个JavaScript异常(例如,抛出“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的调用。


当前回答

编辑2 (2017):

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

编辑1 (2013):

一个更好(也更简单)的解决方案是使用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、它的调用函数等等。

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

其他回答

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

有点晚了,但是,这里有另一个解决方案,它自动检测if参数。callee可用,并使用new Error()。如果没有,就堆叠。 在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();

此填充代码在现代(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. called .caller -在任何浏览器中都不能在严格模式下工作!

在Firefox上比在IE上更容易获得堆栈跟踪,但从根本上来说,这是你想要做的:

将“有问题的”代码段包装在try/catch块中:

try {
    // some code that doesn't work
    var t = null;
    var n = t.not_a_value;
}
    catch(e) {
}

如果你要检查"error"对象的内容,它包含以下字段:

e.fileName:问题产生的源文件/页 e.lineNumber:出现问题的文件/页中的行号 message:描述发生错误类型的简单消息 e.name:发生错误的类型,在上面的例子中它应该是'TypeError' e.stack:包含导致异常的堆栈跟踪

我希望这能帮到你。

这将为现代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)使用的标题“Error”。

它不应该崩溃在旧的浏览器,而只是返回空数组。如果你需要更通用的解决方案,请查看stacktrace.js。它支持的浏览器列表确实令人印象深刻,但在我看来,对于它所打算执行的小任务来说,它太大了:37Kb的精简文本,包括所有依赖项。