抛出异常时如何获取 JavaScript 堆栈跟踪?
堆栈跟踪是一种稳定的方法,用于识别调用程序函数时进入程序的错误。它可以帮助程序员检查特定错误/异常的来源以及其背后的原因。根据收集跟踪数据的时间,这些跟踪的文件大小可能很大。当抛出错误/异常时,我们必须找到一种方法来获取 JavaScript 堆栈跟踪。
堆栈跟踪是程序执行期间特定时间点的活动堆栈帧的报告。当程序运行时,内存通常在堆栈和堆中动态分配。与堆相比,堆栈更活跃,因为它通常是一个连续的内存区域,为每个正在执行的函数分配本地上下文。堆栈也指编程构造,因此该堆栈称为程序的运行时堆栈。一旦在堆栈上分配了一块内存。它不能轻易删除,因为在它之前可能分配了其他内存块。每次在程序中调用函数时,都会在运行时堆栈的顶部分配一块内存,称为激活记录。程序员通常在交互和调试期间使用堆栈跟踪。最终用户可能会看到堆栈跟踪显示为错误消息的一部分,用户可以将其报告给程序员。
堆栈是一种数据结构,其中数据可以以后进先出(LIFO)的形式存储。这意味着堆栈是一种存储,当一组数据进入堆栈时,它会以最后一个数据先删除,第一个数据最后删除的方式逐个存储。堆栈跟踪可以理解任何一组数据存储和从堆栈中删除的方式。
在抛出异常时,我们可以通过以下方法获取 JavaScript 的堆栈跟踪。
使用 console.trace:控制台对象还有一个名为console.trace() 的方法,它可以在控制台上提供跟踪。每次调用时都会为函数生成堆栈跟踪。我们可以借助这个例子来理解这一点。
- 程序:
// Sum function function sum(a, b) { console.trace('sum called with ', a, 'and', b); return a+b; } // Calculation function function calc() { return sum(8, 11) + sum(9, 14); } // Start function function start() { var a = sum(2, 3); var b = calc(); } // Calling start function start();
- 输出:
/usr/bin/node stacktrace.js Trace: add called with 2 and 3 at sum (/home/dev/Documents/stacktrace.js:2:13) at start (/home/dev/Documents/stacktrace.js:11:13) at Object. (/home/dev/Documents/stacktrace.js:16:1) at Module._compile (internal/modules/cjs/loader.js:959:30) at Object.Module._extensions..js (internal/modules/cjs/loader.js:995:10) at Module.load (internal/modules/cjs/loader.js:815:32) at Function.Module._load (internal/modules/cjs/loader.js:727:14) at Function.Module.runMain (internal/modules/cjs/loader.js:1047:10) at internal/main/run_main_module.js:17:11 Trace: add called with 8 and 11 at sum (/home/dev/Documents/stacktrace.js:2:13) at calc (/home/dev/Documents/stacktrace.js:7:12) at start (/home/dev/Documents/stacktrace.js:12:13) at Object. (/home/dev/Documents/stacktrace.js:16:1) at Module._compile (internal/modules/cjs/loader.js:959:30) at Object.Module._extensions..js (internal/modules/cjs/loader.js:995:10) at Module.load (internal/modules/cjs/loader.js:815:32) at Function.Module._load (internal/modules/cjs/loader.js:727:14) at Function.Module.runMain (internal/modules/cjs/loader.js:1047:10) at internal/main/run_main_module.js:17:11 Trace: add called with 9 and 14 at sum (/home/dev/Documents/stacktrace.js:2:13) at calc (/home/dev/Documents/stacktrace.js:7:25) at start (/home/dev/Documents/stacktrace.js:12:13) at Object. (/home/dev/Documents/stacktrace.js:16:1) at Module._compile (internal/modules/cjs/loader.js:959:30) at Object.Module._extensions..js (internal/modules/cjs/loader.js:995:10) at Module.load (internal/modules/cjs/loader.js:815:32) at Function.Module._load (internal/modules/cjs/loader.js:727:14) at Function.Module.runMain (internal/modules/cjs/loader.js:1047:10) at internal/main/run_main_module.js:17:11
使用错误对象:我们可以创建一个错误对象并返回堆栈属性。 Error 对象的非标准堆栈属性为您提供堆栈跟踪,当该特定函数从哪个行和文件调用时,以及使用什么参数。堆栈字符串从最近的调用继续到较早的调用。
// Sum function
function sum(a, b) {
console.log(new Error().stack);
return a+b;
}
// Calculation function
function calc() {
return sum(8, 11) + sum(9, 14);
}
// Start function
function start() {
var a = sum(2, 3);
var b = calc();
}
// Calling start function
start();
/usr/bin/node trace.js
Error
at sum (/home/dev/Documents/trace.js:2:17)
at start (/home/dev/Documents/trace.js:11:13)
at Object. (/home/dev/Documents/trace.js:16:1)
at Module._compile (internal/modules/cjs/loader.js:959:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:995:10)
at Module.load (internal/modules/cjs/loader.js:815:32)
at Function.Module._load (internal/modules/cjs/loader.js:727:14)
at Function.Module.runMain (internal/modules/cjs/loader.js:1047:10)
at internal/main/run_main_module.js:17:11
Error
at sum (/home/dev/Documents/trace.js:2:17)
at calc (/home/dev/Documents/trace.js:7:12)
at start (/home/dev/Documents/trace.js:12:13)
at Object. (/home/dev/Documents/trace.js:16:1)
at Module._compile (internal/modules/cjs/loader.js:959:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:995:10)
at Module.load (internal/modules/cjs/loader.js:815:32)
at Function.Module._load (internal/modules/cjs/loader.js:727:14)
at Function.Module.runMain (internal/modules/cjs/loader.js:1047:10)
at internal/main/run_main_module.js:17:11
Error
at sum (/home/dev/Documents/trace.js:2:17)
at calc (/home/dev/Documents/trace.js:7:25)
at start (/home/dev/Documents/trace.js:12:13)
at Object. (/home/dev/Documents/trace.js:16:1)
at Module._compile (internal/modules/cjs/loader.js:959:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:995:10)
at Module.load (internal/modules/cjs/loader.js:815:32)
at Function.Module._load (internal/modules/cjs/loader.js:727:14)
at Function.Module.runMain (internal/modules/cjs/loader.js:1047:10)
at internal/main/run_main_module.js:17:11
使用调用者对象:我们已经实现了一个名为stacktrace的函数,它将返回一个表示调用历史的字符串到调用stacktrace()的位置。在内部,它使用另一个名为st2的函数,该函数将被递归调用,遍历调用树,直到我们到达 JavaScript 脚本的主体。在 stacktrace 声明的最后,我们使用arguments.callee.caller调用st2 。 arguments 是属于当前函数调用的一个特殊对象,其中包含有关当前调用的大量信息。然后递归调用st2函数并返回到目前为止的堆栈跟踪字符串。
- 程序:
// Sum function function sum(a,b) { // Calling stacktrace function console.log(stacktrace()); return a+b; } // Calculation function function calc() { return sum(8, 11) + sum(9, 14); } // Start function function start() { var a = sum(2, 3); var b = calc(); } // Calling start function start(); // Stacktrace function function stacktrace() { function st2(f) { var args = []; if (f) { for (var i = 0; i < f.arguments.length; i++) { args.push(f.arguments[i]); } var function_name = f.toString(). split('(')[0].substring(9); return st2(f.caller) + function_name + '(' + args.join(', ') + ')' + "\n"; } else { return ""; } } return st2(arguments.callee.caller); }
- 输出:
/usr/bin/node stackt.js ([object Object], function require(path) { return mod.require(path); }, [object Object], /home/dev/Documents/stackt.js, /home/dev/Documents) start() sum(2, 3) ([object Object], function require(path) { return mod.require(path); }, [object Object], /home/dev/Documents/stackt.js, /home/dev/Documents) start() calc() sum(8, 11) ([object Object], function require(path) { return mod.require(path); }, [object Object], /home/dev/Documents/stackt.js, /home/dev/Documents) start() calc() sum(9, 14)