javascript promises.push()立即运行,不等待promises.all()

ryevplcw  于 2023-04-04  发布在  Java
关注(0)|答案(4)|浏览(264)

我有一个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
...

这意味着每次我将一个promise推送到promise []数组(promises.push( await examplePromiseFunc() ))时,函数examplePromiseFunc()都会立即被调用,而不是等待。
我希望我的函数只在最后运行await Promise.all(promises)时才被调用,是不是我遗漏了什么?我的异步函数会导致问题吗?我一直在阅读javascript promises.all,这似乎是一个很好的实现。

e37o9pze

e37o9pze1#

问题是您已经在循环中使用了await,这意味着循环将“等待”并按顺序处理这些项。
相反,你应该只把promises添加到数组中,然后在最后await所有的promises,就像你有:

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);
        
}
3npbholx

3npbholx2#

这里有一个关于Promise构造函数如何工作的基本误解。
构造函数接受一个称为executor的函数参数:

new Promise( executor)

executor函数在构造时被同步调用,有两个函数参数,通常称为resolvereject

executor( resolve, reject)

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

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

多次调用examplePromiseFunct,在该函数中,返回的promise的执行器在构造过程中被同步调用(由Promise)。因此,日志如人们所期望的那样:每次调用examplePromiseFunc时的“examplePromiseFunc()INSIDE”日志。
这种误解可能导致第二个:
Promise.all不“运行”promise-promise是被动对象,以确定性的方式响应调用其关联的resolvereject函数,通过调用附加到它们的fulfilled或rejected处理程序-或者如果用promise解析,则链接另一个promise。
Promise.all简单地返回一个promise,该promise通过其参数promise的已实现结果的数组来实现,或被拒绝,并带有拒绝原因或其参数数组中第一个被拒绝的promise。它在本机代码中有一个执行器,可以有效地将then处理程序附加到其参数数组中的promise,然后被动等待(即,它返回到事件循环),直到一次一个地解决参数承诺。

a5g8bdjr

a5g8bdjr3#

这是因为promise只能这样工作。当你把一个promise推入一个数组时,你已经在等待它了(在循环内)即如果你不等待它们执行,那么它们也会执行,有或没有await promise.all,也有可能所有的promise在你把数组传递到promise.all之前就已经解析了。下面的函数也将解析所有没有promise all的promise。

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() )
        }
}

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

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);
  }
}
fcipmucu

fcipmucu4#

没有什么,只是在这种情况下,你必须使用for infor of循环,因为forEach有时在异步函数中不工作。

相关问题