📜  抛出异常时如何获取 JavaScript 堆栈跟踪?

📅  最后修改于: 2022-05-13 01:56:48.837000             🧑  作者: Mango

抛出异常时如何获取 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)