最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to format a StackTrace using Error.prepareStackTrace? - Stack Overflow

programmeradmin5浏览0评论

(on node version '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._pile (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

Using the native API's getters is not working for me.

How do you format the stackTrace using the native stackTrace API, Error.prepareStackTrace?

(on node version '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._pile (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

Using the native API's getters is not working for me.

How do you format the stackTrace using the native stackTrace API, Error.prepareStackTrace?

Share Improve this question edited Feb 23, 2022 at 6:55 AKUMA no ONI 12k8 gold badges64 silver badges102 bronze badges asked Oct 26, 2015 at 12:25 Игорь НовожиловИгорь Новожилов 611 silver badge3 bronze badges 8
  • captureStackTrace vs prepareStackTrace? – Daniel A. White Commented Oct 26, 2015 at 12:33
  • 1 I still don't understand the question. Those static methods are not being called because the code does not call them, all right. – E_net4 Commented Oct 26, 2015 at 12:40
  • @E_net4 The static method appears to be irrelevant to the question. (But maybe I'm wrong; OP, please clarify?) The interesting question here (for me) is why the class's stack getter is not being called when e.stack is accessed. That is, Error's getter for stack is running instead of tError's getter, even though e is a tError instance. – apsillers Commented Oct 26, 2015 at 12:44
  • 1 My guess is that Error.captureStackTrace() creates an instance stack property, which shadows the getter on the prototype. – Bergi Commented Oct 26, 2015 at 12:49
  • The problem is that "get stack()" is never called, even if to describe the class as: class tError extends Error { get stack() { return 'MyStack'; } }; – Игорь Новожилов Commented Oct 26, 2015 at 14:40
 |  Show 3 more ments

1 Answer 1

Reset to default 8
Your not inheriting from anything when using Error.prepareStackTrace.


About Error.prepareStackTrace


Error.prepareStackTrace is quite different from your typical JS API because it runs your code internally (or it might be better to say Natively). Really your writing the code in JavaScript, but its not a JavaScript API, and it's not a Node API, but rather, its a V8 JavaScript Engine API. Its not something that you can find in other engines.



Parts of the StackTrace


I remember when I first learned about Error.prepareStackTrace, I was really confused because the WebStorm hover widget showed it being a Callback Function. It didn't list all the available API methods I have listed below. Another thing that confused me, was when I read the V8 Documentation on StackTraces (which I suggest you do too if you want to really understand this topic), the docs mentioned CallSites, which threw me off, because I never heard of CallSites. But its important to know, that not only does prepareStackTrace grant access to an array of CallSites, the lines in the standard formatted JavaScript StackTrace that look like...

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

...are the CallSites returned by prepareStackTrace.

In the lines above, you can see 3-parts, all obtainable by the V8 CallSite API's getters.

  1. FilePath
  2. Line Number
  3. Column Number


Using Error.prepareStackTrace



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;
  }
}
This is in TypeScript as that's how I have my editor setup rn, and I wanted to offer a working example. Often times people will do something like I have authored below. This allows the user to get their current position in there code using...
const pos = new Err('')._stack;

This assigns the current row | col in the code to pos.



A couple things to note when using Error.prepareStackTrace are:


  1. Error.prepareStackTrace looks like you would want to use a callback function with it, but really you want to use the Assignment Operator (=) to assign a function to Error.prepareStackTrace. The function you assign will work as if it were a callback.

  2. The function assigned to Error.prepareStackTrace should have two parameters. The first parameter is the Error Object & the second parameter is an array of CallSites. Typically developers call forEach((item, index)=>{ /* do stuff to item */}) on the CallSites parameter to access all available callsites, and do what ever is desired to them.

  3. There is another function associated with this subject, and that is the Error.captureStackTrace method. This is used by the V8 engine when a stackTrace needs to be fetched, but access to the method is not exclusive, as V8 JS developers have access to it.

  4. Error.prepareStackTrace & Error.captureStackTrace are both native V8 JavaScript functions, and are both available for use within the Node.js RTE (written during v16.2.0). Browsers do not support either function.

  5. As stated above, Error.prepareStackTrace is called by the V8 engine automatically. When that happens, the parameters of the function that is assigned to Error.prepareStackTrace are automatically passed the their arguments. The arguments include an Error Object, and that Error Object's Stack-Trace (This is also stated above, if your confused its because you jumped around, and did not read the list in order.).

  6. The stack returned by the snippet above can be manipulated by the following method calls, so long as the data is available. Just because the method is available does not mean that data is available for the method.


  • getThis: returns the value of this
  • getTypeName: returns the type of this as a string. This is the name of the function stored in the constructor field of this, if available, otherwise the object’s [[Class]] internal property.
  • getFunction: returns the current function
  • getFunctionName: returns the name of the current function, typically its name property. If a name property is not available an attempt is made to infer a name from the function’s context.
  • getMethodName: returns the name of the property of this or one of its prototypes that holds the current function
  • getFileName: if this function was defined in a script returns the name of the script
  • getLineNumber: if this function was defined in a script returns the current line number
  • getColumnNumber: if this function was defined in a script returns the current column number
  • getEvalOrigin: if this function was created using a call to eval returns a string representing the location where eval was called
  • isToplevel: is this a top-level invocation, that is, is this the global object?
  • isEval: does this call take place in code defined by a call to eval?
  • isNative: is this call in native V8 code?
  • isConstructor: is this a constructor call?
  • isAsync: is this an async call (i.e. await or Promise.all())?
  • isPromiseAll: is this an async call to Promise.all()?
  • getPromiseIndex: returns the index of the promise element that was followed in Promise.all() for async stack traces, or null if the CallSite is not a Promise.all() call.




LINKS:

  1. V8 Official Documentation - A must read for understanding this topic.

  2. Codota Code Examples - This is good for seeing how others use it.

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

发布评论

评论列表(0)

  1. 暂无评论