【问题标题】:Understanding Error.captureStackTrace and stack trace persistance?了解 Error.captureStackTrace 和堆栈跟踪持久性?
【发布时间】:2020-04-24 18:47:55
【问题描述】:

前段时间我曾经使用joyent的Verror来在重新抛出时不会丢失堆栈跟踪,我刚刚用节点v12做了一个没有Verror的测试,堆栈跟踪似乎在不使用错误的情况下保持不变。

然后我正在查看 Error.captureStackTrace 的使用,它声明在您的错误中使用它,以便错误不会添加到堆栈中。

我不知道我做错了什么,但有或没有 Error.captureStackTrace - 堆栈跟踪是相同的..

我想知道当前使用 captureStackTrace 的状态,因为我认为没有区别 :-) 以及似乎不再需要的 VError 的使用。

在文档中,它指出 .stack 不调用 captureStackTrace 是不可用的,但我每次都看到它可用,不管有没有 captureStackTrace

这里是 2 x 错误的示例

class MyErrorOne extends Error {
  constructor(message) {
    super(message);

    Error.captureStackTrace(this, this.constructor);
  }
}

class MyErrorTwo extends Error {
  constructor(message) {
    super(message);

    Error.captureStackTrace(this, this.constructor);
  }
}

我通过注释掉每个错误中的 captureStackTrace 来尝试它们,并且堆栈跟踪是相同的。

谁能帮忙?

这是我测试调用错误的代码

const DoOne = () => {
  try {
    console.log("executing do one");
    DoTwo();
  } catch (error) {
    console.log("error in DoOne", error);
    console.log("here is the stack ", error.stack);
    throw new MyErrorOne("threw error from doone in myerrorone");
    // throw error;
  }
};

const DoTwo = () => {
  try {
    console.log("executing do two");
    throw new MyErrorTwo("threw error from dotwo in myerrortwo");
  } catch (error) {
    console.log("error in DoTwo", error);
    throw error;
  }
};

DoOne();

【问题讨论】:

    标签: node.js error-handling


    【解决方案1】:

    我不确定,但似乎Error.captureStackTrace 旨在在不扩展Error 类的情况下构造错误对象时使用(另请参阅Node docs 中提供的示例。

    我猜当您扩展 Error 类时,Error 构造函数已经完成了对堆栈跟踪的捕获。

    我已经测试了您的代码并删除了 Error 的扩展,事实上,如果您不调用 captureStackTrace,您将不会在您的错误对象上获得堆栈跟踪。

    我不确定抛出不扩展 Error 类的错误的用例是什么。

    【讨论】:

      【解决方案2】:

      这是我前段时间找到的实现,关键是还原原型链(typescript):

      import {INTERNAL_SERVER_ERROR} from 'http-status-codes';
      
      export class RouteError extends Error {
        public statusCode: number;
        /**
         * Create a new RouteError object to be handled in 'express-async-handler' wrapped middleware.
         * @param message {string} [message=An error occurred.] - The json message key to return to the user.
         * @param statusCode {number} [statusCode=INTERNAL_SERVER_ERROR] - response code to send.
         */
        constructor(message: string = 'An error occurred.', statusCode: number = INTERNAL_SERVER_ERROR) {
          super(message); // 'Error' breaks prototype chain here
          Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain
          this.statusCode = statusCode;
        }
      }
      

      【讨论】:

        【解决方案3】:

        当调用Error.captureStackTrace(obj[, fun]) 时,一个格式化的调用堆栈会附加到obj,包括调用captureStackTrace 的行/帧。

        当指定fun 时,上面的所有帧(包括fun)都将被删除。

        示例:

        注意:在示例输出中,我删除了对 fun1 的调用下方的任何内容,以尽量减少混乱。

        const fun1 = () => { fun2(); };
        const fun2 = () => { fun3(); };
        const fun3 = () => { log_stack(); };
        function log_stack() {
            let err = {};
            Error.captureStackTrace(err);
            console.log(err.stack);
        }
        fun1();
        

        这会产生:

        Error
            at log_stack (/path/to/example.js:6:8)
            at fun3 (/path/to/example.js:3:22)
            at fun2 (/path/to/example.js:2:22)
            at fun1 (/path/to/example.js:1:22)
        

        现在,如果我们将log_stack 作为函数选项添加到captureStackTrace

        Error.captureStackTrace(err, log_stack);
        

        它产生:

        Error
            at fun3 (/path/to/example.js:3:22)
            at fun2 (/path/to/example.js:2:22)
            at fun1 (/path/to/example.js:1:22)
        

        log_stack 框架不再存在。

        fun3 添加到captureStackTrace

        Error.captureStackTrace(err, fun3);
        

        它产生:

        Error
            at fun2 (/path/to/example.js:2:22)
            at fun1 (/path/to/example.js:1:22)
        

        等等

        在你的情况下,如果你改变:

        Error.captureStackTrace(this, this.constructor);
        

        到:

        Error.captureStackTrace(this);
        

        你会看到你得到了额外的一行new MyError...

        error in DoTwo MyErrorTwo: threw error from dotwo in myerrortwo
            at new MyErrorTwo (/path/to/testerrorclass.js:10:9)  <<== Not removed anymore.
        

        【讨论】:

          猜你喜欢
          • 2021-08-21
          • 1970-01-01
          • 1970-01-01
          • 2020-04-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-25
          • 2011-05-13
          相关资源
          最近更新 更多