【问题标题】:How do I use exceptions and promise rejections together in node.js? [duplicate]如何在 node.js 中同时使用异常和承诺拒绝? [复制]
【发布时间】:2020-12-21 18:18:12
【问题描述】:

node.js 中,有没有很好地解释异常如何与承诺的“拒绝”一起工作?

【问题讨论】:

  • “重复”并不能很好地解释异常如何与拒绝承诺一起工作。它被标记为意见。

标签: node.js exception promise


【解决方案1】:

承诺拒绝是同步代码中异常的异步模拟。在 Promise 处理程序中抛出的异常(在 then()catch()finally() 中)会自动转换为 Promise 拒绝。

然而,事实并非如此。如果您创建一个承诺,或调用一个返回最终将被拒绝的承诺的函数,则在 try/catch 块内不会自动转换为异常。但是您可以使用async/await 来完成。这将起作用:

async function() {
    try {
        await getPromiseThatWillBeRejected();
    }
    catch (e) {
        // error that caused rejection can be handled here
    }
}

await 关键字实际上将其转换为同步阻塞调用(它并不是真正的阻塞,但后续代码仅在 promise 完成或拒绝后执行)并将拒绝转换为同步异常。

【讨论】:

    【解决方案2】:

    以下是异常和承诺拒绝组合的演练。

    让我们从一个抛出异常的 Promise 和另一个以拒绝完成 Promise 的 Promise 开始,对它们进行比较。

    function thrower() {
      return new Promise((resolve, reject) => { throw new Error('thrown'); });
    }
    
    function rejecter() {
      return new Promise((resolve, reject) => reject('rejected'));
    }
    

    下面的调用代码同样会收到错误:

    thrower.catch(ex => console.log('caught ' + ex));
    rejecter.catch(ex => console.log('caught ' + ex));
    

    结果是caught Error: throwncaught rejected。到达catch 函数的异常是直截了当的。但奇怪的是,被拒绝的 Promise 也会出现在 catch 函数中。就是这样,让我们​​继续。

    同样,异常变成拒绝。下面使用then的第二个参数提供onrejection函数:

    thrower().then(() => {}, err => console.log('err ' + err));
    rejecter().then(() => {}, err => console.log('err ' + err));
    

    结果是err Error: thrownerr rejected。同样,这是有道理的,拒绝到达onrejection 处理程序。这是一个延伸,但我可以肯定,例外也在那里。

    现在如果同时使用onrejection 处理程序和catch 会怎样?

    thrower().then(() => {}, err => console.log('err ' + err)).catch(ex => console.log('caught ' + ex));
    rejecter().then(() => {}, err => console.log('err ' + err)).catch(ex => console.log('caught ' + ex));
    

    结果是err Error: thrownerr rejected。这里有些混乱。该语言将异常路由到 err 函数,而不是 catch 函数。

    重要的一点,这段代码没有捕捉到异常:

    try {
      thrower();
    }
    catch(ex) {
      console.log('caught ' + ex); // won't catch thrower's exception
    }
    

    为什么 - try/catch 块执行在承诺执行之前完成。

    但这也不太明显:

    function throwerThrower() {
      return new Promise((resolve, reject) => { thrower().catch(ex => { throw ex }); });
    }
    
    throwerThrower().catch(ex => console.log('caught ' + ex));  // not going to catch nested throw
    

    像上面那样级联异常会导致未处理的异常。

    但是下一个块确实有效,并且可能显示拒绝而不是抛出的价值:

    function throwerRejecter() {
      return new Promise((resolve, reject) => { thrower().catch(ex => reject(ex)); });
    }
    throwerRejecter().catch(ex => console.log('caught ' + ex));
    

    最后,这是最后两个嵌套组合:

    function rejecterThrower() {
      return new Promise((resolve, reject) => { rejecter().catch(ex => { throw ex }); });
    }
    rejecterThrower().catch(ex => console.log('caught ' + ex));
    

    返回ERR_UNHANDLED_REJECTION,这看起来很合理,因为拒绝处理引发了异常。

    function rejecterRejecter() {
      return new Promise((resolve, reject) => { rejecter().catch(ex => reject(ex)); });
    }
    rejecterRejecter().catch(ex => console.log('caught ' + ex));
    

    打印caught rejected - 很明显的拒绝的简单级联。

    【讨论】:

    • 您编写了“语言将异常路由到 err 函数,而不是 catch 函数。”如果您知道错误处理程序(then 的第二个参数)与传递给catch() 的参数基本相同,这并不令人困惑。在遇到catch() 之前已经捕获了异常/拒绝。
    猜你喜欢
    • 2011-11-20
    • 1970-01-01
    • 2015-10-09
    • 2016-03-11
    • 2017-02-05
    • 2017-02-06
    • 2014-03-04
    • 2017-06-04
    • 2018-01-18
    相关资源
    最近更新 更多