无法在异步承诺执行程序函数中抛出错误

时间:2017-03-29 03:18:53

标签: javascript node.js promise async-await

我一直试图理解为什么下面的代码没有抓住throw。如果从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>>");
    // ...
  });

}

答案hereherehere重复一遍&#34;如果您在其他任何异步回调中,则必须使用reject& #34;,但是&#34;异步&#34;他们没有提及async函数,所以我不认为他们的解释适用于此(如果他们这样做,我不明白如何)。

如果我们使用throw代替reject,则上述代码可以正常运行。我想明白,从根本上,为什么throw在这里不起作用。谢谢!

2 个答案:

答案 0 :(得分:9)

这是Promise constructor antipattern的异步/等待版本!

Never ever使用async function作为Promise执行函数(即使您可以使其工作 1 )< /子>!

[1:致电resolvereject而非使用returnthrow声明

  

by&#34;异步&#34;他们没有提及async功能,所以我不认为他们的解释适用于此

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

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

相当于

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

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

Promise constructor只能抓住同步例外,而async function 永远不会抛出 - 它总是会返回一个承诺(虽然可能会被拒绝) )。并且忽略该返回值,因为承诺正在等待resolve被调用。

答案 1 :(得分:0)

因为从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函数,因为没有必要。但是某些库(例如手写笔和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
    }
  }
}

显然每个人都说这是一种反模式,但是当我想做一些只能通过回调完成的事情之前不做异步工作时,我会一直使用它(不适用于复制人为的示例之类的文件)。我不明白为什么人们会认为它是一种反模式(使用异步诺言执行器),并且还没有看到使我相信应该接受它作为一般规则的示例。