ECMAScript提案 "错误原因"

197 阅读2分钟

在这篇博文中,我们研究了ECMAScript提案 "错误原因"(由Chengzhong Wu和Hemanth HM提出)。它描述了一个功能,即Error 的实例可以选择性地指定它们是由另一个错误引起的。

为什么我们要把错误连在一起呢?

有时,我们会捕捉到在更深嵌套的函数调用过程中抛出的错误,并希望将更多的信息附加到它上面:

function readFiles(filePaths) {
  return filePaths.map(
    (filePath) => {
      try {
        const text = readText(filePath);
        const json = JSON.parse(text);
        return processJson(json);
      } catch (error) {
        // (A)
      }
    });
}

try 子句里面的语句可能会抛出各种各样的错误。在大多数情况下,错误不会知道引起它的文件的路径。这就是为什么我们想在A行附上这些信息。

如何连锁错误

该提案使我们能够做到以下几点:

function readFiles(filePaths) {
  return filePaths.map(
    (filePath) => {
      try {
        // ···
      } catch (error) {
        throw new Error(`While processing ${filePath}`, {cause: error});
      }
    });
}

Error 和它的子类现在有一个以选项为第二参数的对象。第一个支持的选项是 - 导致当前错误的错误。.cause

对你自己的代码的后果

如果你对Error 进行子类化,那么用选项来支持第二个参数是有意义的:

class MyCustomError extends Error {
  constructor(message, options) {
    super(message, options);
    // ···
  }
}

替代内置的对.cause 的支持

AggregateError (由 创建)Promise.any()

如果 Promise.any()拒绝其返回的Promise,拒绝值是一个AggregateError 的实例,它记录了哪些(零个或多个)错误导致了拒绝:

class AggregateError {
  constructor(errors: Iterable<any>, message: string);
  get errors(): Array<any>;
  get message(): string;
}

AggregateError 然而,如果你的目标引擎不支持 ,这就是一个合理的变通方法:.cause

  • AggregateError 如果我们要处理多个并发的调用,则效果最好。
  • Error 用 ,对单个非并发调用效果最好。.cause

一个自定义的错误类

下面的自定义错误类支持链式:

/**
 * This subclass of Error supports chaining.
 * If available, it uses the built-in support for property `.cause`.
 * Otherwise, it sets it up itself.
 *
 * @see https://github.com/tc39/proposal-error-cause
 */
class CausedError extends Error {
  constructor(message, options) {
    super(message, options);
    if ((isObject(options) && 'cause' in options) && !('cause' in this)) {
      const cause = options.cause;
      this.cause = cause;
      if ('stack' in cause) {
        this.stack = this.stack + '\nCAUSE: ' + cause.stack;
      }
    }
  }
}

function isObject(value) {
  return value !== null && typeof value === 'object';
}

一个库

有几个库支持链式错误,三个例子: