Let’s consider two approaches that look really similar and let’s see how they work behind the scenes and which is the most suggested one. Let’s determine the difference by inspecting how each of the two alternatives works.
// Approach #1:
[await someFunction1(), await someFunction2()];
// Approach #2:
await Promise.all([someFunction1(), someFunction2()]);The first approach (sequential)
[await someFunction1(), await someFunction2()];Here, in an async context, we create an array literal. So, when the someFunction1 is called, a new promise is returned, which then “locks” the async context because the preceding await.
In a nutshell, the await someFunction1() “blocks” the array initialization until the returned promise gets settled (by getting resolved or rejected).
The same process is repeated to someFunction2.
Note that, in this first approach, the two promises are awaited in sequence. There is, therefore, no similarity with the approach that uses Promise.all. Let’s see why.
The second approach (non-sequential)
The Promise.all() method takes an iterable of promises as an input, and returns a single Promise that resolves to an array of the results of the input promises. This returned promise will resolve when all of the input’s promises have resolved, or if the input iterable contains no promises. It rejects immediately upon any of the input promises rejecting or non-promises throwing an error, and will reject with this first rejection message / error.
Promise.all([someFunction1(), someFunction2()]);When the Promise.all is applied, it expects an iterable of promises. It waits for all the promises you give to resolve before returning a new array of resolved values, but it doesn’t wait for each promise to be resolved until waiting for the following one. In essence, it awaits all the promises at the same time, so it is a kind of “non-sequential”.
The Promise.all documentation is available here.

Compare Approach #1 and Approach #2. Who executes first?
Let’s make a real example to compare the two approaches and let’s see who executes first.
Let’s create a simple const delay to delay the execution of a Promise and then create getExecutionTime that accepts a callback async function as a parameter. This simple helper returns a Promise that reports the time needed for the callback execution.
const delay = (timeout: number, value: string) =>
new Promise(resolve => setTimeout(resolve, timeout, value));
const getExecutionTime = async (callback: () => void): Promise<number> => {
const start = new Date().getTime();
await callback();
const end = new Date().getTime();
return end - start;
}
(async function main() {
const executionTimeApporach1 = await getExecutionTime(async () => ([await delay(2000, '1'), await delay(2000, '2')]));
console.log(`Approach #1 lasts: ${executionTimeApporach1} ms`);
const executionTimeApporach2 = await getExecutionTime(async () => (Promise.all([delay(2000, '1'), delay(2000, '2')])));
console.log(`Approach #2 lasts: ${executionTimeApporach2} ms`);
})();Let’s create and execute the main function where both approaches are testes and let’s see the result in the log:
[LOG]: "Approach #1 lasts: 4009 ms"
[LOG]: "Approach #2 lasts: 2008 ms"
We can verify that the Approach #2 using Promise.all takes about half the time of Approach #1.
