我有一个nodejs函数processReviews(workflow),当它被调用时,应该将多个promises推送到一个数组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,这看起来是一个很好的实现。
发布于 2021-01-21 08:53:13
相反,您只需将promises添加到数组中,然后在最后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);
}发布于 2021-01-21 09:49:06
这里对Promise构造函数的工作方式有一个根本性的误解。
构造函数只接受一个称为executor的函数参数
new Promise( executor)在构造过程中,执行器函数被称为同步,它有两个函数参数,通常称为resolve和reject
executor( resolve, reject)promise executor负责启动异步操作(通常),并使resolve和reject函数可用于处理操作完成和错误处理的代码,通常是在回调函数中。
因此代码
for (let i = 0; i < allObjects.length; i++) {
console.log('i=',i,' pushing to promises[]')
promises.push( examplePromiseFunc() )
}多次调用examplePromiseFunct,在该函数中,返回的promise的executor在构造期间被同步调用(由Promise调用)。因此,日志与预期不谋而合:每次调用examplePromiseFunc时,都会出现"examplePromiseFunc() INSIDE“的日志。
这种误解可能会导致第二个误解:
Promise.all不“运行”promise - promises是被动对象,通过调用附加到它们的已履行或已拒绝的处理程序,以确定性的方式响应调用其关联的resolve和reject函数-或者链接另一个promise (如果使用promise解析)。
Promise.all只返回一个promise,该promise由其参数promises的已履行结果数组实现,或者被拒绝,并带有拒绝原因或其参数数组中的第一个promise变为rejected。它在本机代码中有一个执行器,可以有效地将then处理程序附加到其参数数组中的promises,然后被动地等待(即,它返回到事件循环),直到参数promises一次解决一个。
发布于 2021-01-21 10:21:38
这是因为承诺只以这种方式工作。当你将一个promise推入一个数组时,你已经在等待它了(在循环中),也就是说,如果你不想等待它们执行,那么它们也会执行,不管有没有await promise.all,也有可能在你将该数组传递到promise.all之前,所有的promise都已经被解析了。下面的函数还将解析所有没有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);
}
}https://stackoverflow.com/questions/65819710
复制相似问题