【问题标题】:How to wrap a Javascript function so all errors are caught including Promise rejections如何包装 Javascript 函数以便捕获所有错误,包括 Promise 拒绝
【发布时间】:2019-12-14 15:36:53
【问题描述】:

我想编写一个用于包装其他函数的函数,以便捕获所有错误,包括由 Promise 拒绝生成的错误(通常需要 .catch Promise 方法)。

目标是能够包装函数,以便处理所有运行时错误。一个示例用法是我们想要运行的功能,但它是可选的,不是核心业务流程的一部分。如果有错误,我们想报告它并稍后修复它,但我们不希望它停止程序流程。

它应该能够用任意数量的参数包装函数,并返回与原始函数相同的值,包括原始函数是否返回一个承诺。

我是否正在处理以下所有可能的情况?有没有更简单的方法来做到这一点?

const catchAllErrors = (fn) => (...args) => {
  try {
    const possiblePromise = fn(...args);

    // Is it a promise type object? Can't use "instanceof Promise" because just
    // for example, Bluebird promise library is not an instance of Promise.
    if (typeof possiblePromise.catch === 'function') {
      return Promise.resolve(possiblePromise).catch((error) => {
        console.log('Caught promise error.', error);
      });
    }

    return possiblePromise;

  } catch (error) {
    console.log('Caught error.', error);
  }
};

// EXAMPLE USAGE

// Applying the wrapper to various types of functions:

const throwsErr = catchAllErrors((x, y) => {
  throw `Error 1 with args ${x}, ${y}.`;
});

const promiseErr = catchAllErrors((a, b) => Promise.reject(`Error 2 with args ${a}, ${b}.`));

const noError = catchAllErrors((name) => `Hi there ${name}.`);

const noErrorPromise = catchAllErrors((wish) => Promise.resolve(`I wish for ${wish}.`));

// Running the wrapped functions:

console.log(throwsErr(1, 2));

promiseErr(3, 4).then((result) => console.log(result));

console.log(noError('folks'));

noErrorPromise('sun').then((result) => console.log(result));

【问题讨论】:

    标签: javascript ecmascript-6 promise try-catch


    【解决方案1】:

    不要试图自己检测某件事是否是一个承诺。使用 Promise 解析的内置 thenable 检测。您可以使用Promise 构造函数来捕获异常:

    const catchAllErrors = (fn) => (...args) => {
      return new Promise(resolve => {
        resolve(fn(...args));
      }).catch((error) => {
        console.log('Caught error.', error);
      });
    };
    

    或者直接使用async/await 语法:

    const catchAllErrors = (fn) => async (...args) => {
      try {
        return await fn(...args);
      } catch (error) {
        console.log('Caught error.', error);
      }
    };
    

    (如果您仍然使用 Bluebird,也可以为此调用它的 Promise.try method

    【讨论】:

    • 看起来您的代码没有返回被包装的原始函数的值?在我的代码中,如果包装函数返回一个承诺,我只会返回一个承诺。
    • 我不一定使用 Bluebird。只是希望它也适用于 Bluebird。不过感谢您的提示。
    • @ToddChaffee 我不认为您需要返回结果,因为当出现错误时,您只会得到undefined?但可以肯定的是,如果你真的愿意,你可以 return 承诺,但我认为在这些情况下,调用者应该自己处理错误(并且还要知道他们调用的函数是否是异步的)。
    • @ToddChaffee 如果您在某些情况下对undefined 感到满意,但不是在所有情况下都可以,这听起来仍然很奇怪……我宁愿将console.log 放在cathAllErrors 回调中(如果出现异常,可能根本不会调用它)。但是如果你真的有这个要求,你的原始代码可能没问题,我唯一要改变的是检查 .then 而不是 .catch 是一个函数。
    • @ToddChaffee 因为that's the check that Promise.resolve does itselfcatch(…)反正是没有意义的,只是then(undefined, …)的别名
    猜你喜欢
    • 2018-03-24
    • 2012-01-16
    • 2021-04-21
    • 2017-02-05
    • 2016-09-18
    • 1970-01-01
    • 1970-01-01
    • 2019-01-04
    • 2021-09-08
    相关资源
    最近更新 更多