Jarrod Tanton
Jarrod Tanton

Reputation: 43

JavaScript: Promise.All() and Async / Await and Map()

I'm trying to understand why the following two code blocks yield different results.

Code Block one works as expected and returns an array of the providers looked up from the database. On the other hand, Code Block two returns an array of functions. I feel like I'm missing something simple here in my understanding of Promise.all() and async / await.

The differences in the code blocks are:

In case you aren't familiar with the Sequelize library, the findOne() method that gets called returns a promise.

Also worth mentioning, I know that I could use a single find query with and "name in" where clause to get the same results without creating an array of promises for multiple select queries. I'm doing this simply as a learning exercise on async / await and Promise.all().

CODE BLOCK 1: Using map() inside Promise.all()

private async createProfilePromises(profiles){

    let profileProviderFindPromises = [];

    //Build the Profile Providers Promises Array.
    profiles.forEach(profile => {
        profileProviderFindPromises.push(
            () => {
                return BaseRoute.db.models.ProfileProvider.findOne({
                    where: {
                        name: {[BaseRoute.Op.eq]: profile.profileProvider}
                    }
                })}
        );
    });

    //Map and Execute the Promises
    let providers = await Promise.all(profileProviderFindPromises.map(async (myPromise) =>{
        try{
            return await myPromise();
        }catch(err){
            return err.toString();
        }
    }));

    //Log the Results
    console.log(providers);
}

CODE BLOCK 2: Adding the async function without the use of map()

private async createProfilePromises(profiles){

    let profileProviderFindPromises = [];

    //Build the Profile Providers Promises Array.
    profiles.forEach(profile => {
        profileProviderFindPromises.push(
            async () => {
                try{
                    return await BaseRoute.db.models.ProfileProvider.findOne({
                        where: {
                            name: {[BaseRoute.Op.eq]: profile.profileProvider}
                        }
                    });
                }catch(e){
                    return e.toString();
                }
            }
        );
    });

    //Execute the Promises
    let providers = await Promise.all(profileProviderFindPromises);

    //Log the Results
    console.log(providers);
}

Upvotes: 4

Views: 8231

Answers (1)

Jonas Wilms
Jonas Wilms

Reputation: 138307

Your code basically boils down to:

  const array = [1, 2, 3];

  function fn() { return 1; }

  array.map(fn); // [1, 1, 1]

  array.push(fn);
  console.log(array); // [1, 2, 3, fn]

You push a function (whether that is async or not does not matter), instead you want to push the result of calling the function:

  array.push(fn());

or in your case:

 array.push((async () => { /*...*/ })());

How I'd write your code:

 return Promise.all(profiles.map(async profile => {
   try{
     return await BaseRoute.db.models.ProfileProvider.findOne({
       where: {
         name: { [BaseRoute.Op.eq]: profile.profileProvider }
       }
     });
  } catch(e) {
    // seriously: does that make sense? :
    return e.toString();
  }
}));

Upvotes: 7

Related Questions