【问题标题】:How to format a StackTrace using Error.prepareStackTrace?如何使用 Error.prepareStackTrace 格式化 StackTrace?
【发布时间】:2015-10-26 12:25:51
【问题描述】:

(在节点版本 '4.2.1'、v8 '4.5.103.35' 上)

    var TE = class tError extends Error {
       constructor(message) {
          super(message);
          this.name = tError.name;
          Error.captureStackTrace(this, tError);
       }
       static prepareStackTrace() {
          console.log('run is prepareStackTrace');
          return 'MyPrepareStack'
       }
       get stack() {
          console('getter stack');
          return 'MyStack';
       }
    };
    
    TE.stackTraceLimit = 1;
    
    console.log('ErrorPrepare:', TE.prepareStackTrace);
    
    var e = new TE('MyError');
    console.log('ErrorName: ', e.name);
    console.log('ErrorStack: ', e.stack);
OUTPUT:

    D:\>node ./Error
    ErrorPrepare: prepareStackTrace() {
          console.log('run is prepareStackTrace');
          return 'MyPrepareStack'
       }
    ErrorName:  tError
    ErrorStack:  tError: MyError
        at Object.<anonymous> (D:\Error.js:23:9)
        at Module._compile (module.js:435:26)
        at Object.Module._extensions..js (module.js:442:10)
        at Module.load (module.js:356:32)
        at Function.Module._load (module.js:311:12)
        at Function.Module.runMain (module.js:467:10)
        at startup (node.js:134:18)
        at node.js:961:3

使用本机 API 的 getter 不适合我。

如何使用本机 stackTrace API Error.prepareStackTrace 格式化 stackTrace?

【问题讨论】:

  • captureStackTrace vs prepareStackTrace?
  • 我还是不明白这个问题。那些静态方法没有被调用,因为代码没有调用它们,好吧。
  • @E_net4 静态方法似乎与问题无关。 (但也许我错了;OP,请澄清一下?)这里(对我来说)有趣的问题是为什么在访问 e.stack 时没有调用类的 stack getter。也就是说,Errorstack 的 getter 正在运行,而不是 tError 的 getter,即使 etError 实例。
  • 我的猜测是Error.captureStackTrace() 创建了一个实例stack 属性,它会影响原型上的getter。
  • 问题是永远不会调用“get stack()”,即使将类描述为:class tError extends Error { get stack() { return 'MyStack'; } };

标签: javascript node.js v8 stack-trace


【解决方案1】:
你在使用Error.prepareStackTrace时没有继承任何东西。


关于Error.prepareStackTrace


Error.prepareStackTrace 与您的典型 JS API 完全不同,因为它在内部运行您的代码(或者说 Natively 可能更好)。真的是用 JavaScript 编写代码,但它不是 JavaScript API,也不是 Node API,而是 V8 JavaScript Engine API。它不是您在其他引擎中可以找到的。



StackTrace 的部分


我记得当我第一次了解Error.prepareStackTrace 时,我真的很困惑,因为 WebStorm 悬停小部件显示它是一个回调函数。它没有列出我在下面列出的所有可用 API 方法。让我感到困惑的另一件事是,当我阅读 V8 Documentation on StackTraces(如果你想真正理解这个主题,我建议你也这样做)时,文档提到了 CallSites,这让我很反感,因为我从未听说过 CallSites。但重要的是要知道,prepareStackTrace 不仅授予对 CallSites 数组的访问权限,标准格式的 JavaScript StackTrace 中的行看起来像...

'at' /foo/foo.js:11:32
'at' /foo/bar.js:59:22

...是 prepareStackTrace 返回的 CallSites。

在上面的行中,您可以看到 3 部分,都可以通过 V8 CallSite API 的 getter 获得。

  1. 文件路径
  2. 行号
  3. 列号


使用Error.perpareStackTrace



export class Err extends Error {
  _stack?:string;
  constructor(message: string) {
    super(message);
    const _prepareStackTrace = Error.prepareStackTrace;

    Error.prepareStackTrace = (_, callsites) => {
      callsites.forEach(callsite => {
        callsite.getLineNumber();
        callsite.getColumnNumber();
      });
    };

    this._stack = this.stack;

    Error.prepareStackTrace = _prepareStackTrace;
  }
}
这是在 TypeScript 中,因为这就是我的编辑器设置 rn 的方式,我想提供一个工作示例。很多时候人们会做一些我在下面写的事情。这允许用户使用...获得他们在代码中的当前位置...
const pos = new Error('')._stack;

这将分配当前行 |代码中的col到pos



使用Error.prepareStackTrace 时需要注意以下几点:


  1. Error.prepareStackTrace 看起来您想要使用回调函数,但实际上您想要使用 赋值运算符 (=) 来分配一个Error.prepareStackTrace 的函数。您分配的函数将像回调一样工作。

  2. 分配给Error.prepareStackTrace 的函数应该有两个参数。第一个参数是 错误对象,第二个参数是 CallSites 数组。通常,开发人员在 CallSites 参数上调用 forEach((item, index)=&gt;{ /* do stuff to item */}) 以访问所有可用的调用站点,并执行他们想要的任何操作。

  3. 还有一个与这个主题相关的函数,那就是Error.captureStackTrace方法。当需要获取 stackTrace 时,V8 引擎会使用此方法,但对方法的访问不是独占的,因为 V8 JS 开发人员可以访问它。

  4. Error.prepareStackTraceError.captureStackTrace 都是原生 V8 JavaScript 函数,都可以在 Node.js RTE 中使用(在 v16.2.0 期间编写)。浏览器不支持这两种功能。

  5. 如上所述,Error.prepareStackTrace 由 V8 引擎自动调用。发生这种情况时,分配给Error.prepareStackTrace 的函数的参数会自动传递给它们的参数。参数包括 Error Object,以及 Error Object's Stack-Trace(这也在上面说明,如果你的困惑是因为你跳来跳去,并没有按顺序阅读列表。)。

  6. 上面sn-p返回的栈可以通过下面的方法调用来操作,只要有数据即可。仅仅因为方法可用并不意味着该方法的数据可用。


  • getThis:返回this的值
  • getTypeName:以字符串形式返回 this 的类型。这是存储在 this 的构造函数字段中的函数名称,如果可用,否则为对象的 [[Class]] 内部属性。
  • getFunction:返回当前函数
  • getFunctionName:返回当前函数的名称,通常是它的 name 属性。如果名称属性不可用,则尝试从函数的上下文中推断名称。
  • getMethodName:返回 this 或其包含当前函数的原型之一的属性名称
  • getFileName:如果此函数在脚本中定义,则返回脚本的名称
  • getLineNumber:如果此函数在脚本中定义,则返回当前行号
  • getColumnNumber:如果此函数在脚本中定义,则返回当前列号
  • getEvalOrigin:如果此函数是使用调用 eval 创建的,则返回一个字符串,表示调用 eval 的位置
  • isToplevel:这是顶级调用吗,也就是说,这是全局对象吗?
  • isEval:此调用是否发生在通过调用 eval 定义的代码中?
  • isNative:这个调用是原生 V8 代码吗?
  • isConstructor:这是一个构造函数调用吗?
  • isAsync:这是一个异步调用(即 await 或 Promise.all())吗?
  • isPromiseAll:这是对 Promise.all() 的异步调用吗?
  • getPromiseIndex:返回 Promise.all() 中跟踪异步堆栈跟踪的 promise 元素的索引,如果 CallSite 不是 Promise.all() 调用,则返回 null。 H5>




链接:

  1. V8 Official Documentation - 理解这个主题的必读。

  2. Codota Code Examples - 这对了解其他人如何使用它很有帮助。

  3. NPM Module that implements Error.prepareStackTrace for you.

【讨论】:

    猜你喜欢
    • 2021-08-04
    • 2022-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-05
    • 1970-01-01
    相关资源
    最近更新 更多