微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

promises.push() 立即运行并且不等待 promises.all()

如何解决promises.push() 立即运行并且不等待 promises.all()

我有一个 nodejs 函数 processReviews(workflow),当调用它时,应该将多个 promise 推送到数组 promises[],然后在 for 循环后使用 promises.all() 运行它们。

function examplePromiseFunc(){
    return new Promise((resolve,reject) => {
        console.log("examplePromiseFunc() INSIDE ")
        resolve('done')
    })
}

async function processReviews(workflow){
        //get objects from s3
        let allObjects = await getAllObjects(workflow);
        allObjects = allObjects.filter(obj => obj.Key.includes('output.json'))
        console.log(`found ${allObjects.length} .json files.`)

        const promises = [];
        for (let i = 0; i < allObjects.length; i++) {
            console.log('i=',i,' pushing to promises[]')
            promises.push( examplePromiseFunc() )
        }

        const result = await Promise.all(promises)
        console.log('running,result = ',result);
}

但是当我运行我的代码时,输​​出看起来像这样:

found 697 .json files.
i= 0  pushing to promises[]
examplePromiseFunc() INSIDE
i= 1  pushing to promises[]
examplePromiseFunc() INSIDE
i= 2  pushing to promises[]
examplePromiseFunc() INSIDE
i= 3  pushing to promises[]
examplePromiseFunc() INSIDE
...

这意味着每次我向 promises[] 数组 (promises.push( await examplePromiseFunc() )) 推送一个 promise 时,函数 examplePromiseFunc() 都会立即被调用并且不会等待。

我希望我的函数只在最后运行 await Promise.all(promises) 时才被调用,有什么我遗漏的吗?我的异步函数会导致问题吗?我一直在阅读 javascript promises.all,这似乎是一个很好的实现。

解决方法

问题是您已经在循环中使用了 await,这意味着循环将“等待”并按顺序处理项目。

相反,您应该将承诺添加到数组中,然后像您一样在最后 await 所有:

async function processReviews(workflow) {
  //get objects from s3
  const allObjects = await getAllObjects(workflow);

  const promises = [];
  for (let i = 0; i < allObjects.length; i++) {
    // Don't await the promise here,just start it and add it to the array.
    promises.push(examplePromiseFunc(allObjects[i]));
  }
  const result = await Promise.all(promises)
  console.log(result);
        
}
,

这里对 Promise 构造函数的工作原理存在一个根本性的误解。

构造函数接受一个称为 executor 的函数参数:

new Promise( executor)

执行器函数在构造过程中同步调用,带有两个通常称为resolvereject的函数参数:

executor( resolve,reject)

promise executor 负责启动异步操作(通常)并使 resolvereject 函数可用于处理操作完成和错误处理的代码,通常在回调函数中。

因此代码

    for (let i = 0; i < allObjects.length; i++) {
        console.log('i=',i,' pushing to promises[]')
        promises.push( examplePromiseFunc() )
    }

多次调用 examplePromiseFunct 并且在该函数内,返回的承诺的执行器在构造期间被同步调用(通过 Promise)。因此,日志正如人们所期望的:每次调用 examplePromiseFunc 时都会记录“examplePromiseFunc() INSIDE”的日志。

这个误会很可能会导致第二个误会:

Promise.all 不“运行”承诺 - 承诺是被动对象,通过调用附加到他们 - 或者如果用承诺解决,则链接另一个承诺。

resolve 简单地返回一个承诺,该承诺由其参数承诺的已履行结果数组完成,或者被拒绝原因或参数数组中第一个被拒绝的承诺。它在本机代码中有一个执行程序,可以有效地将 reject 处理程序附加到其参数数组中的承诺,然后被动等待(即返回到事件循环),直到一次解决一个参数承诺。

,

那是因为 Promise 只能以这种方式工作。当您将承诺推入数组时,您已经在等待它(在循环内),即如果您不等待它们执行,那么它们也会执行,有或没有 await promise.all,也有可能所有的 Promise 在你在 promise.all 中传递那个数组之前已经解决了。 下面的函数也将在没有全部承诺的情况下解决所有承诺。

async function processReviews(workflow){
        //get objects from s3
        let allObjects = await getAllObjects(workflow);
        allObjects = allObjects.filter(obj => obj.Key.includes('output.json'))
        console.log(`found ${allObjects.length} .json files.`)

        const promises = [];
        for (let i = 0; i < allObjects.length; i++) {
            console.log('i=',' pushing to promises[]')
            promises.push( examplePromiseFunc() )
        }
}

此外,您不应该无限制地使用 promise.all,因为它可能会达到您的硬件限制。 使用有限制的地图可以减少您的问题。

async function processReviews(workflow) {
  //get objects from s3
  let allObjects = await getAllObjects(workflow);
  allObjects = allObjects.filter(obj => obj.Key.includes("output.json"));
  console.log(`found ${allObjects.length} .json files.`);

  for (let i = 0; i < allObjects.length; i = i + PROMISE_LIMIT) {
    const objects = allObjects.slice(i,i + PROMISE_LIMIT);
    const result = await Promise.all(objects.map(elem => examplePromiseFunc()));
    console.log("running,result = ",result);
  }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。