A. Atiyah
A. Atiyah

Reputation: 555

Nested Promises - Map function inside a map function

basically I have a big array with object values like this:

[{
  - Champion Name
  - [Another Array with Skins information]
}]

so what I want to do is run a map function inside the second array to get a value for everyone of these skins so what I did was.

const got = require('got');
const cheerio = require('cheerio');
const fs = require('fs').promises;

const getSkinData = async champSkins => {
  const data = JSON.parse(champSkins);

  const handleMap = skin => {
    return new Promise(async (resolve, reject) => {
      try {
        const name = skin.split(' ').join('_');

        const { body } = await got(`https://lol.gamepedia.com/${name}`);

        const $ = cheerio.load(body);

        const skinLink = $('.InfoboxSkin img').attr('src') || '';

        const skinInfo = {
          skinName: skin,
          skinLink
        };

        resolve(skinInfo);
      } catch (err) {
        console.error(err.message);
      }
    });
  };

  Promise.all(
    data.map(async ({ skins }) => {
      return Promise.all(
        skins.map(skin => {
          return handleMap(skin);
        })
      );
    })
  ).then(data => console.log(data));
};

module.exports = getSkinData;

but it didn't actually work, I couldn't access the data and the console.log inside the promise at the end didn't even run.

any idea how to do it or is there a better way to do it?

EDIT #1

basically 'skins' for every champ is an array of strings like:

[ 'Aatrox',          
  'Justicar Aatrox', 
  'Mecha Aatrox',    
  'Sea Hunter Aatrox'
  'Blood Moon Aatrox'
  'Blood Moon Aatrox 
  'Victorious Aatrox' ]

[ 'Ahri',            
  'Dynasty Ahri',    
  'Midnight Ahri',   
  'Foxfire Ahri',    
  'Popstar Ahri',    
  'Challenger Ahri', 
  'Academy Ahri',    
  'Arcade Ahri',     
  'Star Guardian Ahri
  'K/DA Ahri',       
  'K/DA Ahri Prestige
  'Elderwood Ahri' ] 

and skin is just every value of the array

and the value that comes back from the scraping is just a link for each skin

enter image description here

Upvotes: 0

Views: 128

Answers (1)

Aplet123
Aplet123

Reputation: 35560

const getSkinData = async champSkins => {
    const data = JSON.parse(champSkins);
    // async that returns promise is a double promise, you only need async
    const handleMap = async skin => {
        try {
            const name = skin.split(" ").join("_");
            const { body } = await got(`https://lol.gamepedia.com/${name}`);
            const $ = cheerio.load(body);
            const skinLink = $(".InfoboxSkin img").attr("src") || "";
            const skinInfo = {
                skinName: skin,
                skinLink
            };
            // changed resolve to return
            return skinInfo;
        } catch (err) {
            console.error(err.message);
        }
    };

    return await Promise.all(data.map(({ skins }) => Promise.all(skins.map(skin => handleMap(skin)))));
};

Async functions return a promise that resolves with their return value, so returning a promise from an async function is redundant and ends up causing a nested promise. Also, you don't have to use .then in async functions because you can just await the promise. Read more about Promises and async/await.

Upvotes: 1

Related Questions