繁体   English   中英

Promise 数组和异步函数的问题

[英]Troubles with promise array and async functions

我试图使用异步函数来实现 Promise.all 函数。 但是当其中一个承诺被拒绝时,我得到一个错误。 这是我所做的实现:

    async function Promise_All_II(promises){
        let results = []
        for(let p of promises)
            results.push(await p)
        return results
    }

    const takeTime = (value, time=1000) => new Promise(resolve => setTimeout(resolve, time, value))

    let promises = [
        Promise.resolve(1),
        takeTime(2),
        Promise.reject('You are fairly dump'),
        takeTime(3)
    ]
    
    console.log('Promise all II:')
    Promise_All_II(promises).then(console.log, console.log)

这是当其中一个承诺被拒绝时我得到的错误:

Promise all II:
(node:9399) UnhandledPromiseRejectionWarning: You are fairly dump
(node:9399) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:9399) [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 exit code.
You are fairly dump
(node:9399) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)

我试图用 try-catch 包装for 循环,但它没有用。 我还尝试在p之后放置和.catch ,但仍然没有用。

我注意到当您尝试执行以下操作时会发生相同的错误:

let f = async () => {
    let ps = [
        Promise.resolve(10),
        Promise.reject(10),
        Promise.resolve(11),
        Promise.resolve(12)
    ]
    for(let p of ps)
        await p
}

f().catch(v => 
    console.log('something happened')
)

有人能帮助我吗?

在 nodejs 中,当解释器返回事件循环时,如果您将被拒绝的 Promise 留在没有.catch()处理程序的地方,您将收到有关未处理拒绝的错误。 这意味着您不能在await某个其他承诺时将被拒绝的承诺留在变量中。 这将触发未处理的拒绝错误。 JS 解释器不够聪明,无法知道您稍后会收到拒绝。

所以,当你这样做时:

results.push(await p)

并且,任何其他 Promise 被拒绝,您将得到未处理的拒绝,因为被拒绝的 Promise 在它拒绝时没有处理程序来处理拒绝,并且await会导致解释器返回事件循环。 解释器看到你处于空闲状态,一个承诺被拒绝并且它没有拒绝处理程序,从而触发错误。

因此,由于未处理的拒绝在 nodejs 中的工作方式,实际上没有办法像您尝试使用awaitfor循环那样实现这一点,因为这使得其他承诺在await期间没有拒绝处理程序。

Promise.all()的通常实现包括创建您自己的 Promise 并使用计数器来跟踪所有问题何时解决。 而且,您会立即在每个 Promise 上安装 resolve 和 reject 处理程序,这样它们就不会处于导致未处理的拒绝处理程序的状态。

这是Promise.all()的简单实现,您可以在此代码段中运行它:

 function Promise_All_II(promises) { return new Promise((resolve, reject) => { let cntr = 0; let length = 0; let results; for (let p of promises) { // keep track of index, for later use with result let i = length++; Promise.resolve(p).then(val => { results[i] = val; ++cntr; if (cntr === length) { resolve(results); } }).catch(reject); } if (length === 0) { resolve([]); return; } results = new Array(length); }); } const takeTime = (value, time=1000) => new Promise(resolve => setTimeout(resolve, time, value)) let promises = [ Promise.resolve(1), takeTime(2), Promise.reject('You are fairly dump'), takeTime(3) ]; console.log('Promise all II:') Promise_All_II(promises).then(console.log, console.log);

这会立即在每个 Promise 上安装 resolve 和 reject 处理程序,从而避免未处理的拒绝错误。

注意, Promise_All_II()的调用者还必须有一个拒绝处理程序。


需要注意的几个细节:

  1. 这适用于任何可迭代的,而不仅仅是按照Promise.all()规范的数组。 它甚至不必具有.length属性。
  2. 根据Promise.all()规范,这实现了“快速拒绝”(例如,一旦任何承诺拒绝就拒绝)。
  3. 根据Promise.all()规范,这允许非承诺值在可迭代中。 这就是我们使用Promise.resolve(p).then(...)的原因,因此任何普通值都会被包装,然后我们可以将其视为承诺。

暂无
暂无

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

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