【问题标题】:Node.JS - Can`t get async throws with try/catch blocksNode.JS - 无法使用 try/catch 块获得异步抛出
【发布时间】:2018-09-03 10:20:52
【问题描述】:

当我在节点中创建一个异步函数并使用 await 时,我正在等待一个承诺解决(可以是解决或拒绝),我所做的就是放置一个await 在 try/catch 块中承诺并在承诺被拒绝的情况下抛出错误。问题是,当我在 try/catch 块中调用此异步函数以捕获错误时,我会收到 UnhandledPromiseRejectionWarning。但是使用 await 的全部意义不是等待承诺解决并返回它的结果吗?看起来我的异步函数正在返回一个承诺。

示例 - UnhandledPromiseRejectionWarning 的代码:

let test = async () => {
   let promise = new Promise((resolve, reject) => {
      if(true) reject("reject!");
      else resolve("resolve!");
   });
   try{
      let result = await promise;
   }
   catch(error) {
      console.log("promise error =", error);
      throw error;
   }
}

let main = () => {
   try {
      test();
   }
   catch(error){
      console.log("error in main() =", error);
   }
}

console.log("Starting test");
main();

【问题讨论】:

标签: javascript node.js async-await


【解决方案1】:

异步函数总是返回承诺。事实上,它们总是返回原生的 Promise(即使你返回了一个 bluebird 或一个常量)。 async/await 的重点是降低.then回调地狱的版本。您的程序仍然必须在 main 函数中至少有一个 .catch 来处理任何到达顶部的错误。

对于顺序异步调用非常好,例如;

async function a() { /* do some network call, return a promise */ }

async function b(aResult) { /* do some network call, return a promise */ }

async function c() {
   const firstRes = (await (a() /* promise */) /* not promise */);
   const secondRes = await b(firstRes/* still not a promise*/);
}

你不能await 不在函数内部。通常这意味着您的 main 函数或 init 或任何您称之为的函数都不是异步的。这意味着它不能调用await 并且必须使用.catch 来处理任何错误,否则它们将是未处理的拒绝。在节点版本的某个时刻,这些将开始占用您的节点进程。

async 视为返回原生承诺 - 无论如何 - 将 await 视为“同步”解包承诺。

  • 注意异步函数返回原生承诺,它们不会同步解析或拒绝:

    Promise.resolve(2).then(r => console.log(r)); console.log(3); // 3 printed before 2
    Promise.reject(new Error('2)).catch(e => console.log(e.message)); console.log(3); // 3 before 2
    
  • 异步函数将同步错误作为被拒绝的承诺返回。

    async function a() { throw new Error('test error'); }
    
    // the following are true if a is defined this way too
    async function a() { return Promise.reject(new Error('test error')); }
    
    /* won't work */ try { a() } catch(e) { /* will not run */ }
    
    /* will work */ try { await a() } catch (e) { /* will run */ }
    
    /* will work */ a().catch(e => /* will run */)
    
    /* won't _always_ work */ try { return a(); } catch(e) { /* will not usually run, depends on your promise unwrapping behavior */ }
    

【讨论】:

  • 好的,但是我已经在函数 test 中使用了 try/catch 块来处理 promise 的拒绝。为什么我不能在函数 main 中抛出错误并得到这个错误?
  • 无论你做什么,异步函数都会返回一个承诺。你可以从字面上做async () => 2,这仍然会返回一个承诺。 async/await 的好处在于它标准化了所有返回,而不管 async 函数内部发生了什么。这样我们就不必处​​理有时会同步抛出,有时会返回一个被拒绝的 Promise 的函数。
  • @HenriqueBorges 要明确 - 测试是一个异步函数,它永远不会抛出传统 - 必须等待它或使用 .catch
  • 哦,我现在明白了,非常感谢@Catalyst 的耐心和解释。我真的很感激。现在回到代码:)
  • 也许值得再举一个例子,try { return a(); } catch(e) {} 不起作用。我被这个抓住了——当将 Promise.then.catch 模式转换为 async / await 函数时,很容易对函数中的最终承诺不做等待,因为它是多余的。但是,如果您还将它包含在 try / catch 块中,则 catch 将永远不会起作用,因为缺少 await 意味着块内的异常 / 拒绝永远不会“解包”。 return await a() 会被抓到,return a() 不会。
【解决方案2】:

Main 必须是异步函数才能捕获异步错误

// wont work
let main = () =>{
    try{
        test();
    }catch(error){
        console.log("error in main() =", error);
    }
}

// will work
let main = async () =>{
    try{
        test();
    }catch(error){
        console.log("error in main() =", error);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-18
    • 1970-01-01
    • 1970-01-01
    • 2012-02-20
    • 2020-12-16
    • 2011-03-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多