Search code examples
javascriptarraysnode.jspromisees6-promise

Using "map" with promises returns ordered and unordered results


I have this piece of code:

const Axios = require('axios');
const baseURL = 'https://jsonplaceholder.typicode.com';

async function main() {
    const posts = await Axios(`${baseURL}/posts`);
    const users = await Promise.all(posts.data.map( async (post, index) => {
        let d = await Axios(`${baseURL}/users/${post.userId}`);
        return d.data.name;
    }))

    users.map( (user, index) => {
        console.log( `${index}. ${user}` );
    });
}

And outputs the result in order:

1. Patricia
2. Glenna
3. Nicholas
4. Kurtis
5. Chelsey

Everything Ok, but ... If I do:

async function main() {
    const posts = await Axios(`${baseURL}/posts`);
    await Promise.all(posts.data.map( async (post, index) => {
        let d = await Axios(`${baseURL}/users/${post.userId}`);
        console.log( `${index}. ${d.data.name}` );
    }))
}

the console.log inside map prints the list unordered ...

2. Glenna
4. Kurtis
5. Chelsey
1. Patricia
3. Nicholas

My question is:

Why in the first code map returns the list ordered, and in the second one the console.log inside map, prints the list unordered ?


Solution

  • Promise.all is designed to keep the order of the results of the promises that were passed to it, independent of the order those promises actually resolved. So when Promise.all resolves, it means all individual promises resolved, and then Promise.all resolves to the array of resolutions in the same order as the corresponding promises have in the array.

    If however you output the values as soon as their promises resolve, then the above has of course no effect on your output -- it will now be ordered by the order in which the individual promises resolve.

    Simple example:

    Let's say there are three promises p1,p2, p3 that resolve to 1, 2 and 3. But the second promise will resolve sooner than the other two.

    Promise.all is called with [p1, p2, p3]. It returns a new promise that will eventually resolve to [1, 2, 3]. During the time that not all promises are resolved, you could imagine that an internal array evolves as follows:

    • p2 resolves. Promise.all internally stores [undefined, 2, undefined]
    • p1 resolves. Promise.all internally stores [1, 2, undefined]
    • p3 resolves. Promise.all also resolves with value [1, 2, 3]

    Here you can see that the first code would output 2, 1, 3 while the second would output 1, 2, 3