Reputation: 525
I'm trying to run few async functions in parallel/concurrently.
I found two solutions but don't know the difference between them. they either use Promise.all or addition symbol.
Also I don't see a point of checking the results if one function throws an exception.
await Promise.all([asyncFunction01(), asyncFunction02()])
const [p1, p2] = await Promise.all([asyncFunction01(), asyncFunction02()])
const p1 = asyncFunction01()
const p2 = asyncFunction02()
await p1 + await p2
const p1 = asyncFunction01()
const p2 = asyncFunction02()
const result = await p1 + await p2
They all seem run the same to me. They all run in parallel and fail fast in case of an error was thrown. I like the third option because it looks neater.
So what are the differences? Am I missing something?
Upvotes: 3
Views: 220
Reputation: 72256
A Promise
is an object that represents the eventual completion (or failure) of an asynchronous operation, and its resulting value.
When a Promise
object is created (when new Promise()
returns), the asynchronous operation has already been started and it will run and complete with success or failure no matter if it is await
-ed or not.
await
-ing a Promise
is just a way to accomplish these things:
await
the code that launches the async operation usually completes before the async operation; await
pauses it until the async operation completes and resumes it afterwards, allowing the execution of multiple async operations in series (useful when a later operation depends on results produced by an operation that must run before it);Regarding the asynchronous processing, await p1 + await p2
has the same results as await p1; await p2
. The p1
promise is awaited to complete then the p2
promise is awaited to complete. If p2
completes before p1
, await p2
returns immediately.
The purpose of Promise.all()
is not to "run the promises in parallel". The promises do not run, they are just data (the results of the asynchronous code). The asynchronous code behind the promises runs and it runs "in parallel" because this is what asynchronous code does by its nature. It doesn't need Promise.all()
to do that.
The purpose of Promise.all()
is to produce a mechanism to easily await
for all the wrapped promises and to capture the resolved values of all wrapped Promise
s into a single value (an array).
It also fails when one of the wrapped Promise
objects fails.
For the completion/fail part, await p1 + await p2
is, more or less, equivalent to await Promise.all([p1, p2])
.
Capturing and returning the resolved values of p1
and p2
is a different story.
await p1 + await p2
works only if the resolved values of p1
and p2
can be combined using the +
operator. It doesn't work with arrays and objects. It doesn't work even with numbers when the results must be combined in a different way.
Upvotes: 1
Reputation: 2119
There isn't a difference! Just two alternative ways to achieve it.
return5 = async () => new Promise(
resolve => setTimeout(resolve.bind(null, 5),250)
);
return8 = async () => new Promise(
resolve => setTimeout(resolve.bind(null, 8),300)
);
g = async () => {
console.time('await +');
p1a = return5(); // async task started here
p2a = return8(); // async task started here
// waiting for them to all finish here and are printed
console.log(await p1a + await p2a);
console.timeEnd('await +');
console.time('Promise all');
// async tasks started immediately when the promises are passed
// as well as waiting for their completion here
const [p1, p2] = await Promise.all([return5(), return8()]);
// results are here and printed sync
console.log(p1 + p2);
console.timeEnd('Promise all');
}
g();
Upvotes: 2
Reputation: 6975
Adding two awaited promises together may or may not run in parallel, depending on when you initialize them. If you initialize them in the addition statement itself, they will run in series; the first one runs, then when it's done, the second one runs. See:
const p1 = () => new Promise((resolve, reject) => {
setTimeout(() => {
console.log('p1')
resolve(200)
}, 5000)
})
const p2 = () => new Promise((resolve, reject) => {
setTimeout(() => {
console.log('p2')
resolve(100)
}, 3000)
})
async function start() {
const result = await p1() + await p2()
console.log(result)
Promise.all([p1(), p2()])
}
start()
If adding the awaited promises together made them run in series, you'd see p2
finish before p1
. That isn't the case. However, when you run them using Promise.all, you see that p2
finishes first.
As @Kaiido pointed out in the comments, the OP shows starting the promises before awaiting them to add together. In that case, they will run in parallel:
const P1 = () => new Promise((resolve, reject) => {
setTimeout(() => {
console.log('p1')
resolve(200)
}, 5000)
})
const P2 = () => new Promise((resolve, reject) => {
setTimeout(() => {
console.log('p2')
resolve(100)
}, 3000)
})
async function start() {
const p1 = P1()
const p2 = P2()
const result = await p1 + await p2
console.log(result)
}
start()
You'll see that p2 finishes before p1. So you're right, there is functionally no difference. So depending on your use case, they'll work exactly the same. Some thoughts though:
I think Promise.all is more clear. You're explicitly signaling to other developers (and your future self) that you want those promises to run in parallel.
With Promise.all you don't have to create variables for each promise. In many cases, Promise.all will be cleaner. Though in your example of adding the two results together, using Promise.all will probably not be any cleaner:
const result = await Promise.all([p1(), p2()]
.then(([r1, r2]) => r1 + r2)
Upvotes: 3