繁体   English   中英

无法从异步承诺执行器函数中抛出错误

[英]Can't throw error from within an async promise executor function

我一直试图从概念上理解为什么下面的代码没有捕捉到throw 如果您从new Promise(async (resolve, ... part ) 中删除async关键字new Promise(async (resolve, ...则它可以正常工作,因此它与 Promise 执行器是异步函数这一事实有关。

(async function() {

  try {
    await fn();
  } catch(e) {
    console.log("CAUGHT fn error -->",e)
  }

})();

function fn() {

  return new Promise(async (resolve, reject) => {
    // ...
    throw new Error("<<fn error>>");
    // ...
  });

}

此处此处此处的答案重复“如果您处于任何其他异步回调中,则必须使用reject ”,但是“异步”不是指async函数,因此我认为它们的解释不适用在这里(如果他们这样做,我不明白如何)。

如果我们使用reject而不是throw ,则上面的代码可以正常工作。 我想从根本上了解为什么throw在这里不起作用。 谢谢!

这是Promise构造函数反模式的异步/等待版本!

从来没有使用async function作为Promise执行程序功能(即使你可以把它工作1)!

[1:通过调用resolvereject而不是使用returnthrow语句]

通过“异步”,他们不是指async函数,所以我认为他们的解释不适用于这里

他们也可以。 无法工作的一个简单示例是

new Promise(async function() {
    await delay(…);
    throw new Error(…);
})

这相当于

new Promise(function() {
    return delay(…).then(function() {
        throw new Error(…);
    });
})

现在很清楚throw在异步回调中。

Promise构造函数只能捕获同步异常,而async function永远不会抛出- 它总是返回一个Promise (尽管可能会被拒绝)。 并且该返回值被忽略,因为承诺正在等待resolve被调用。

因为从 Promise 执行器内部与外部世界“通信”的唯一方法是使用resolvereject函数。 您可以使用以下示例:

function fn() {
  return new Promise(async (resolve, reject) => {
    // there is no real reason to use an async executor here since there is nothing async happening
    try {
      throw new Error('<<fn error>>')
    } catch(error) {
      return reject(error);
    }
  });
}

例如,当您想做一些具有方便的异步功能但也需要回调的事情时。 以下人为示例通过使用异步fs.promises.readFile函数和基于回调的fs.writeFile函数读取文件来复制文件。 在现实世界中,您永远不会像这样混合fs函数,因为没有必要。 但是一些库,如 stylus 和 pug 使用回调,我在这些场景中一直使用这样的东西。

const fs = require('fs');

function copyFile(infilePath, outfilePath) {
  return new Promise(async (resolve, reject) => {
    try {
      // the fs.promises library provides convenient async functions
      const data = await fs.promises.readFile(infilePath);
      // the fs library also provides methods that use callbacks
      // the following line doesn't need a return statement, because there is nothing to return the value to
      // but IMO it is useful to signal intent that the function has completed (especially in more complex functions)
      return fs.writeFile(outfilePath, data, (error) => {
        // note that if there is an error we call the reject function
        // so whether an error is thrown in the promise executor, or the callback the reject function will be called
        // so from the outside, copyFile appears to be a perfectly normal async function
        return (error) ? reject(error) : resolve();
      });
    } catch(error) {
      // this will only catch errors from the main body of the promise executor (ie. the fs.promises.readFile statement
      // it will not catch any errors from the callback to the fs.writeFile statement
      return reject(error);
      // the return statement is not necessary, but IMO communicates the intent that the function is completed
    }
  }
}

显然每个人都说这是一种反模式,但是当我想在做一些只能用回调完成的事情之前做一些异步的事情时,我一直使用它(而不是像我人为的例子那样复制文件)。 我不明白为什么人们认为这是一种反模式(使用异步承诺执行器),并且还没有看到一个例子让我相信它应该被接受为一般规则。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM