Как я могу получить трассировку стека JavaScript при выдаче исключения?
Если я выброшу исключение 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
,
25 ответов
Изменить 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);
}
Обратите внимание, что chromium/chrome (другие браузеры, использующие V8), а также Firefox имеют удобный интерфейс для получения трассировки стека через свойство стека объектов Error.
try {
// Code throwing an exception
} catch(e) {
console.log(e.stack);
}
Это относится как к базовым исключениям, так и к тем, которые вы сами выбрасываете. (Считается, что вы используете класс Error, который в любом случае является хорошей практикой).
Подробности смотрите в документации V8
В Firefox кажется, что вам не нужно бросать исключение. Достаточно сделать
e = new Error();
console.log(e.stack);
Если у вас есть firebug, на вкладке скрипта есть опция break on all errors. Как только сценарий достигнет вашей точки останова, вы можете посмотреть на окно стека firebug:
Хорошим (и простым) решением, как указано в комментариях к исходному вопросу, является использование 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
объект! Вы можете добавить интервал между линиями трассировки и полностью отключить его. Вот оно с Console.trace
установлен в false
:
Вы даже можете отключить первый бит показанной информации (установить Console.settings.debug.showInfo
в false
) или полностью отключить отладку (установить Console.settings.debug.enabled
в false
) так что вам больше никогда не придется комментировать отладочную инструкцию! Просто оставьте их, и это ничего не сделает.
Я не думаю, что есть что-то встроенное, что вы можете использовать, но я нашел много примеров, когда люди катались самостоятельно.
С браузером Chrome вы можете использовать console.trace
метод: https://developer.chrome.com/devtools/docs/console-api
Вы можете получить доступ к stack
(stacktrace
в опере) свойства Error
экземпляр, даже если вы бросили его. Дело в том, что вы должны убедиться, что вы используете throw new Error(string)
(не забывайте новое вместо throw string
,
Пример:
try {
0++;
} catch (e) {
var myStackTrace = e.stack || e.stacktrace || "";
}
Это даст трассировку стека (в виде массива строк) для современных 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).
Он не должен вылетать в старых браузерах, а просто возвращать пустой массив. Если вам нужно более универсальное решение, посмотрите на http://www.stacktracejs.com/. Его список поддерживаемых браузеров действительно впечатляет, но, на мой взгляд, он очень большой для той небольшой задачи, для которой он предназначен: 37 КБ минимизированного текста, включая все зависимости.
Обновление ответа Юджина: объект ошибки должен быть брошен для IE (определенные версии?), Чтобы заполнить stack
имущество. Следующее должно работать лучше, чем его текущий пример, и должно избегать возврата undefined
когда в IE.
function stackTrace() {
try {
var err = new Error();
throw err;
} catch (err) {
return err.stack;
}
}
Примечание 1: Подобные действия следует выполнять только при отладке и отключать при работе, особенно если они часто вызываются. Примечание 2: Это может работать не во всех браузерах, но, похоже, работает в FF и IE 11, что вполне соответствует моим потребностям.
Один из способов получить реальную трассировку стека в 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()
показывает трассировку стека.
Этот полифилл-код работает в современных (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 - не работает в строгом режиме ни в одном браузере!
Функция:
function print_call_stack(err) {
var stack = err.stack;
console.error(stack);
}
вариант использования:
try{
aaa.bbb;//error throw here
}
catch (err){
print_call_stack(err);
}
В 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
Надеюсь, это поможет.
function stacktrace(){
return (new Error()).stack.split('\n').reverse().slice(0,-2).reverse().join('\n');
}
по крайней мере, в Edge 2021:
console.groupCollapsed('jjjjjjjjjjjjjjjjj')
console.trace()
try {
throw "kuku"
} catch(e) {
console.log(e.stack)
}
console.groupEnd()
traceUntillMe()
и ты закончил мой друг
<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>
этот скрипт покажет ошибку
В некотором роде поздно, но вот еще одно решение, которое автоматически определяет, если доступен arguments.callee, и использует новый стек 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();
Вот ответ, который дает вам максимальную производительность (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>" );
})();
Вы можете использовать эту библиотеку 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>
Ничего себе - я не вижу ни одного человека за 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
работал для меня раньше, а теперь нет - так что я не уверен, что происходит.
С помощью console.error(e.stack)
Firefox показывает только трассировку стека в журналах,
Chrome также показывает сообщение. Это может быть неприятным сюрпризом, если сообщение содержит важную информацию. Всегда регистрируйте оба.
Легче получить трассировку стека в 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: номер строки в файле / странице, на которой возникла проблема. e.message: простое сообщение с описанием типа ошибки e.name: тип ошибки, которая произошла, в приведенном выше примере это должно быть 'TypeError' e.stack: содержит трассировку стека, вызвавшую исключение
Я надеюсь, что это помогает вам.
Мне пришлось исследовать бесконечную рекурсию в smartgwt с IE11, поэтому для более глубокого исследования мне потребовалась трассировка стека. Проблема заключалась в том, что я не смог использовать консоль разработчика, потому что воспроизведение было сложнее.
Используйте следующее в методе javascript:
try{ null.toString(); } catch(e) { alert(e.stack); }