【问题标题】:Unhandled promise rejection with Promise.allSettled and try/catch使用 Promise.allSettled 和 try/catch 处理未处理的承诺拒绝
【发布时间】:2021-08-02 18:01:36
【问题描述】:

我的想法如下: 我想同时发送多个请求,而不必等到之前的执行。

所以我的伪代码如下:

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

function failingRequest(){
    return new Promise((resolve, reject) => {
        reject('Request failed');
    });
}

function successRequest(){
    return new Promise((resolve, reject) => {
        resolve('Request success');
    });
}

async function main() {
    try {
        let executions = [];
        executions.push(failingRequest());
        await sleep(4000);
        executions.push(successRequest());
        let result = await Promise.allSettled(executions);
        console.log(result);
    } catch (err) {
        console.log('Outer error occured.');
        console.log(err.message);
    }

    console.log('done');
}
main();

在这里运行此代码可以在浏览器中按预期工作,但会给我以下与节点一起运行的输出:

node:761) UnhandledPromiseRejectionWarning: Request failed
api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:761) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exi not handled will terminate the Node.js process with a non-zero exit code.
[
  { status: 'rejected', reason: 'Request failed' },
  { status: 'fulfilled', value: 'Request success' }
]
done
(node:761) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)

知道为什么会这样吗?

请注意,我只插入了sleep,因此我可以测试catch 块是否会在第一个请求失败的情况下被执行这不是所需的行为。我想同时发起这些请求,我不在乎是否失败。我想稍后通过let result = await Promise.allSettled(executions); 检查哪些请求有效,哪些请求失败。我希望这很清楚。

【问题讨论】:

标签: javascript node.js promise try-catch


【解决方案1】:

知道为什么会这样吗?

您创建 failingRequest(),然后等待 4 秒再处理它。

我只插入了睡眠,所以我可以测试

...因此您导致了未处理的拒绝。删除await sleep(4000);,它会按预期工作!

【讨论】:

  • 如果我像这样添加这些功能 100 万次 let executions = []; for(let i = 0; i < 1000000; i++) { executions.push(failingRequest()); executions.push(successRequest()); } 第一次拒绝似乎也没有立即处理,而且任何Unhandled promise rejection 仍然不会...
  • 是的,它由Promise.allSettled(executions) 调用立即(=同步)处理。但随后它会等待 4 秒 之后 来解决这些承诺,然后再记录所有执行的结果。
【解决方案2】:

有趣的问题 - 问题是您实际上并没有模拟异步请求。实际上,您的两个请求方法只是创建同步/立即解决/拒绝的承诺。您需要将await 放在failingRequest() 之前,以便在try/catch 周围捕获被拒绝的承诺,但这可能不是您想要的。

您不应该立即“开始”承诺,而应该是这样的:

try {
        let executions = [];
        executions.push(failingRequest);
        await sleep(4000);
        executions.push(successRequest);
        let result = await Promise.allSettled(executions.map(promiseFn => promiseFn()));
        console.log(result);
    } catch (err) {
        console.log('Outer error occured.');
        console.log(err.message);
    }

这将记录

[
  { status: 'rejected', reason: 'Request failed' },
  { status: 'fulfilled', value: 'Request success' }
]
done

正如预期的那样。

【讨论】:

  • 有趣的答案。我没有想到这一点,它似乎工作......但回到我原来的测试:如果让我们说一个请求在 10 秒后超时,这会阻止执行 catch 块吗?我需要确保所有executions 都将被执行,无论他们是单独解决还是拒绝。
  • 是的,如果你这样做,保证所有的执行都会被执行。您甚至可以通过在请求函数中添加setTimeout 来模拟它。我已经为您创建了一个修改版本的代码,它可能会帮助您了解正在发生的事情:jsfiddle.net/1rfpksvu
  • 这太棒了!我想知道如何将参数应用于这些函数,但 .bind() 成功了。谢谢!
  • 我不明白你为什么要这样做。您同样可以在创建 executions 数组之前移动 await sleep(4000); 行。
  • 我试图说明的一点是,promise 是与 OP 的原始代码同步/立即执行的,并且由于await sleep(..),立即拒绝的 promise 不再被捕获。当然,在我的示例中,await sleep 没有多大意义,但我决定保留它以便 OP 理解。
猜你喜欢
  • 1970-01-01
  • 2018-07-09
  • 1970-01-01
  • 2020-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多