可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
If I throw a JavaScript exception myself (eg, throw \"AArrggg\"
), how can I get the stack trace (in Firebug or otherwise)? Right now I just get the message.
edit: As many people below have posted, it is possible to get a stack trace for a JavaScript exception but I want to get a stack trace for my exceptions. For example:
function foo() {
bar(2);
}
function bar(n) {
if (n < 2)
throw \"Oh no! \'n\' is too small!\"
bar(n-1);
}
When foo
is called, I want to get a stack trace which includes the calls to foo
, bar
, bar
.
回答1:
A modified version of this snippet may somewhat help:
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);
}
EDIT 2 (2017) :
In all modern browsers you can simply call: console.trace();
(MDN Reference)
EDIT 1 (2013):
A better (and simpler) solution as pointed out in the comments on the original question is to use the stack
property of an Error
object like so:
function stackTrace() {
var err = new Error();
return err.stack;
}
This will generate output like this:
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
Giving the name of the calling function along with the URL, its calling function, and so on.
回答2:
Note that chromium/chrome (other browsers using V8), and also Firefox do have a convenient interface to get a stacktrace through a stack property on Error objects.
try {
// Code throwing an exception
} catch(e) {
console.log(e.stack);
}
It applies for the base exceptions as well as for the ones you throw yourself. (Considered that you use the Error class, which is anyway a good practice).
See details on V8 documentation
回答3:
In Firefox it seems that you don\'t need to throw the exception. It\'s sufficient to do
e = new Error();
console.log(e.stack);
回答4:
If you have firebug, there\'s a break on all errors option in the script tab. Once the script has hit your breakpoint, you can look at firebug\'s stack window:
回答5:
I don\'t think there\'s anything built in that you can use however I did find lots of examples of people rolling their own.
- DIY javascript stack trace
- A Javascript stacktrace in any browser
回答6:
A good (and simple) solution as pointed out in the comments on the original question is to use the stack
property of an Error
object like so:
function stackTrace() {
var err = new Error();
return err.stack;
}
This will generate output like this:
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
Giving the name of the calling function along with the URL and line number, its calling function, and so on.
I have a really elaborate and pretty solution that I have devised for a project I am currently working on and I have extracted and reworked it a bit to be generalized. Here it is:
(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);
Check it out on GitHub (currently v1.2)! You can use it like Console.debug(\"Whatever\");
and it will, depending on the settings in Console
, print the output and a stack trace (or just simple info/nothing extra at all). Here\'s an example:
Make sure to play around with the settings in the Console
object! You can add spacing between the lines of the trace and turn it off entirely. Here it is with Console.trace
set to false
:
You can even turn off the first bit of info shown (set Console.settings.debug.showInfo
to false
) or disable debugging entirely (set Console.settings.debug.enabled
to false
) so you never have to comment out a debug statement again! Just leave them in and this will do nothing.
回答7:
You can access the stack
(stacktrace
in Opera) properties of an Error
instance even if you threw it. The thing is, you need to make sure you use throw new Error(string)
(don\'t forget the new instead of throw string
.
Example:
try {
0++;
} catch (e) {
var myStackTrace = e.stack || e.stacktrace || \"\";
}
回答8:
one way to get a the real stack trace on Firebug is to create a real error like calling an undefined function:
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);
Or use console.error()
followed by a throw
statement since console.error()
shows the stack trace.
回答9:
With Chrome browser, you can use console.trace
method: https://developer.chrome.com/devtools/docs/console-api#consoletraceobject
回答10:
An update to Eugene\'s answer: The error object must be thrown in order for IE (specific versions?) to populate the stack
property. The following should work better than his current example, and should avoid returning undefined
when in IE.
function stackTrace() {
try {
var err = new Error();
throw err;
} catch (err) {
return err.stack;
}
}
Note 1: This sort of thing should only be done when debugging, and disabled when live, especially if called frequently. Note 2: This may not work in all browsers, but seems to work in FF and IE 11, which suits my needs just fine.
回答11:
This will give a stack trace (as array of strings) for modern Chrome, Opera, Firefox and 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);
}
Usage:
console.log(getStackTrace().join(\'\\n\'));
It excludes from the stack its own call as well as title \"Error\" that is used by Chrome and Firefox (but not IE).
It shouldn\'t crash on older browsers but just return empty array. If you need more universal solution look at stacktrace.js. Its list of supported browsers is really impressive but to my mind it is very big for that small task it is intended for: 37Kb of minified text including all dependencies.
回答12:
In Google Chrome (version 19.0 and beyond), simply throwing an exception works perfectly. For example:
/* 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();
will show the stack trace at the browser\'s console output:
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
Hope this help.
回答13:
<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>
this script will show the error
回答14:
function:
function print_call_stack(err) {
var stack = err.stack;
console.error(stack);
}
use case:
try{
aaa.bbb;//error throw here
}
catch (err){
print_call_stack(err);
}
回答15:
This polyfill code working in modern (2017) browsers (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;
}
Other answers:
function stackTrace() {
var err = new Error();
return err.stack;
}
not working in IE 11 !
Using arguments.callee.caller - not working in strict mode in any browser!
回答16:
You could use this library http://www.stacktracejs.com/ . It\'s very good
From documentation
You can also pass in your own Error to get a stacktrace not available
in IE or 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>
回答17:
function stacktrace(){
return (new Error()).stack.split(\'\\n\').reverse().slice(0,-2).reverse().join(\'\\n\');
}
回答18:
It is easier to get a stack trace on Firefox than it is on IE but fundamentally here is what you want to do:
Wrap the \"problematic\" piece of code in a try/catch block:
try {
// some code that doesn\'t work
var t = null;
var n = t.not_a_value;
}
catch(e) {
}
If you will examine the contents of the \"error\" object it contains the following fields:
e.fileName : The source file / page where the issue came from
e.lineNumber : The line number in the file/page where the issue arose
e.message : A simple message describing what type of error took place
e.name : The type of error that took place, in the example above it should be \'TypeError\'
e.stack : Contains the stack trace that caused the exception
I hope this helps you out.
回答19:
Kind of late to the party, but, here is another solution, which autodetects if arguments.callee is available, and uses new Error().stack if not.
Tested in chrome, safari and firefox.
2 variants - stackFN(n) gives you the name of the function n away from the immediate caller, and stackArray() gives you an array, stackArray()[0] being the immediate caller.
Try it out at 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();
回答20:
I had to investigate an endless recursion in smartgwt with IE11, so in order to investigate deeper, I needed a stack trace. The problem was, that I was unable to use the dev console, because the reproduction was more difficult that way.
Use the following in a javascript method:
try{ null.toString(); } catch(e) { alert(e.stack); }
回答21:
Wow - I don\'t see a single person in 6 years suggesting that we check first to see if stack
is available before using it! The worst thing you can do in an error handler is throw an error because of calling something that doesn\'t exist.
As others have said, while stack
is mostly safe to use now it is not supported in IE9 or earlier.
I log my unexpected errors and a stack trace is pretty essential. For maximum support I first check to see if Error.prototype.stack
exists and is a function. If so then it is safe to use 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: It appears that since stack
is a property and not a method you can safely call it even on older browsers. I\'m still confused because I was pretty sure checking Error.prototype
worked for me previously and now it doesn\'t - so I\'m not sure what\'s going on.
回答22:
Using console.error(e.stack)
Firefox only shows the stacktrace in logs,
Chrome also shows the message.
This can be a bad surprise if the message contains vital information. Always log both.
回答23:
Here is an answer that gives you max performance (IE 6+) and max compatibility. Compatible with 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>\" );
})();
回答24:
Just try
throw new Error(\'some error here\')
This works pretty well for chrome: