如果我有一个元素数组,并且我想对它们执行并行操作。
我会用promise.all()
。
我知道promise.all()
接受一系列承诺。如果我错了,就纠正我,我不这么认为。
这里,上面写得很清楚。
Promise.all()方法返回一个单独的承诺,当作为可迭代的所有承诺都已实现时,或者当可迭代的承诺不包含承诺时,或者当可迭代包含已实现的承诺和已返回的非承诺时,该承诺就会履行。它以拒绝第一个承诺的原因拒绝,或者拒绝第一个参数捕获的错误,如果该参数使用try/catch/ that块捕获了其中的一个错误。
因此,是的,我们可以将简单的函数传递给promise.all()
,如果它们返回,它将解析,如果它们抛出错误,则会拒绝。
现在看下面的代码。
const promises = todayAssignedJobs.map(async todayAssigned => {
const [leaderboard, created] = await Leaderboard.findOrCreate({...});
if (!created) {
const rating = (todayAssigned.rating + leaderboard.rating * leaderboard.jobs_completed) / (leaderboard.jobs_completed + 1);
const commission = todayAssigned.commission + leaderboard.commission;
const jobsCompleted = leaderboard.jobs_completed + 1;
await Leaderboard.update({
rating,
commission,
jobs_completed: jobsCompleted,
updated_by: 'system',
}, {
where: {
id: leaderboard.id,
},
});
}
await AssignedJob.update({
is_leaderboard_generated: true,
}, {
where: {
id: todayAssigned.id,
},
});
});
await Promise.all(promises);
在这里,我有一个疑问。
我们正在对数组的每个元素进行迭代,并对它们进行异步操作。他们没有明确地返回任何东西。
所以,我认为map在这里也在做并行操作。
为什么shuold在这里使用promise.all()
?
发布于 2020-04-23 05:15:03
.map()
并没有承诺。所以,当你像你一样传递给它一个async
回调时,它不会注意到返回的承诺。因此,它只是一个接一个地运行循环,而不是等待任何返回的承诺。因此,在.map()
循环中启动的所有异步操作都将同时正常运行。
如果这是您想要的,并且您希望收集所有返回的承诺,这样您以后就可以看到它们什么时候都用Promise.all()
完成了,那么这个模式运行得很好:
Promise.all(someArray.map(callbackThatReturnsAPromiseHere))
这是一种常见的设计模式。事实上,蓝知更鸟承诺库有一个特殊的功能,它将这两者结合起来称为Promise.map()
。它还提供了另一个很好的特性,允许您控制一次可以运行多少并发异步操作(因为它的map()
操作具有承诺感知能力)。
这听起来像是在试图弄清楚是否应该只使用.map()
而不使用Promise.all()
。如果这样做,您将并行地运行异步操作,但您将不知道这些操作何时完成,也不知道收集所有结果的能力。您可以在返回的承诺数组上使用Promise.all()
来知道它们什么时候完成和/或收集它们的解析结果。
.map()
只是一个简单的循环。它没有任何特殊的异步特性或任何特殊的并行运行特性。如果您愿意,可以使用for
循环做同样的事情。它不会让您的async
回调暂停等待它被执行,因此运行它的一个副作用是您启动了一系列并行异步操作。
发布于 2020-04-23 05:15:08
只有当所有操作都完成时,您才需要Promise.all
。例如:
const promises = todayAssignedJobs.map(async todayAssigned => {
// lots of async stuff
});
await Promise.all(promises);
// now, all Promises have resolved
// alert the user that the leaderboard is completely updated
如果一旦确定所有承诺都完成了,就不需要发生任何事情,那么Promise.all
就没有意义了--您最好还是在一个循环中创建这些承诺,并将它们保持原样。在这种情况下,由于您不会使用得到的承诺数组,所以使用forEach
(这是用于副作用的数组方法)更为合适。
不过,有一个问题--您不是在处理错误,而是应该处理错误,否则它们会发出警告或退出Node进程:
const processJob = async (todayAssigned) => {
const [leaderboard, created] = await Leaderboard.findOrCreate({...});
if (!created) {
// ...
// ...
todayAssignedJobs.forEach(async todayAssigned => {
try {
await processJob(todayAssigned);
} catch(e) {
// handle errors
}
});
发布于 2020-04-23 05:15:35
在这里,Promise.all
的目的是能够等待所有的承诺才能继续。
如果您在紧接console.log之前添加了一个await Promise.all(promises);
,那么它将在任何承诺解决之前同步运行,而在该行之后的console.log将仅在所有承诺解析后才会出现。
https://stackoverflow.com/questions/61379705
复制相似问题