从可能是异步的回调中捕获并返回错误

Catching and returning an error from a callback that may be asynchronous

我有这样的功能:

const x = y(callback);
x();

它可以通过同步或异步回调调用:

const a = y(() => 42);
const b = y(async () => Promise.resolve(42));

函数y 应该接受回调,可以是同步的也可以是异步的。是否可以从同步或异步回调中捕获抛出的错误?

我不能简单地将回调包装在 try/catch:

const y = (callback) => function () {
  try {
    return callback(...arguments);
  }
  catch (callbackError) {
    throw callbackError;
  }
};

因为它没有捕捉到 promises 抛出的错误。我不能将 .catch 链接到回调上,因为它可能不是一个承诺。

我读过在调用一个函数之前检查它是否是一个 promise may not trivial/may not be possible

我无法在将 catch 链接到它之前调用它来检查它是否 return 是一个 promise,因为如果它抛出,catch 就不会被链接到通话

有没有办法从可能是也可能不是承诺的回调中捕获错误?


根据评论,我应该指定我不希望函数 return 承诺。即:

const a = y(() => { throw new Error(); })();
console.log(a instanceof Error);

const b = y(async () => { throw new Error(); })();
console.log(b instanceof Error);

const c = y(() => 42)();
console.log(c === 42);

const d = y(async () => Promise.resolve(42))();
console.log(d instanceof Promise);

应该都是真的。简单的说,我要return一个错误或者结果

异步函数也会发出一个承诺,您可能会考虑将异步包装在一个承诺中,它在解析时发出值

好吧,你可以通过让你的所有代码异步来做这样的事情......如果我解决你的问题。

UPD:明白问题所在,这是我的做法

(async () => {

  // Run fn
  const fn = callback => {
    return new Promise(async (resolve, reject) => {
        const res = await callback().catch(err => reject(err));
        // Resolve
        resolve(res);
    });
  };

  const variousFNs = [
    // Function 1
    {
      fn: () => 2+2
    },
    // Function 2 with error
    {
      fn: () => {
        const x = 1;
        x = 2;
        return x;
      }
    },
    // Promise Function 3
    {
      fn: () => Promise.resolve(8)
    },
    // Promise function 4 with error
    {
      fn: () => new Promise(async (resolve, reject) => reject('some promise error'))
    }
  ];
  
  //
  //
  // Run all your fns
  for (let i = 0; i < variousFNs.length; i++) {
    try {
      const res = await variousFNs[i].fn();
      console.log(res);
    } catch(err) {
      console.log(`Error catched: ${err}`);
    }
  }

})();

意识到没有必要立即链接 catch!所以下面的可憎之处允许我确定它是否是一个承诺并相应地处理错误:

const y = (error, callback) => function () {
  try {
    const returnValue = callback(...arguments);

    if (returnValue instanceof Promise) {
      return returnValue.catch((callbackError) => {
        return callbackError;
      });
    }
    else {
      return returnValue;
    }
  }
  catch (callbackError) {
    return callbackError;
  }
};

如果您想知道为什么这个函数有用,这里有一个我使用它的例子。它在 return 之前修改错误(将其与另一个错误链接,参见 VError):

const y = (error, callback) => function () {
  try {
    const returnValue = callback(...arguments);

    if (returnValue instanceof Promise) {
      return returnValue.catch((callbackError) => {
        throw VError(error, callbackError);
      });
    }
    else {
      return returnValue;
    }
  }
  catch (callbackError) {
    throw VError(error, callbackError);
  }
};

根据问题注意以下return:

const a = y(() => 42)(); // returns '42'
const b = y(async () => Promise.resolve(42))(); // returns 'Promise {42}'
const c = y(() => { throw new Error('Base'); })(); // throws VError
const d = y(async () => { throw new Error('Base'); })(); // throws VError

您可以在此处使用 async/await 表示法。 Await 将与同步和异步函数一起使用。

尝试做:

async function init() {
  const x = y( async () => await callback() );
  try {
    await x();
  }
  catch(error) {
    /.../
  }
}

你的函数现在可以简化为:


const y = (callback) => function (...argument) {
    return callback(...arguments); 
};