console.log () показывает перед выполнением обещания - PullRequest
0 голосов
/ 18 апреля 2019

Мне нужно сопоставить массив с чем-то вроде 4000 позиций, и мне нужно запустить эту карту внутри Обещания, но я не могу этого сделать: @

Что делает код? Я иду в MongoDB и получаю все данные, которые мне нужны:

const axios = require('axios');
const cheerio = require('cheerio');
const MongoClient = require('mongodb').MongoClient;
const rp = require('request-promise');

let mongoConnection = 'connectionString';
let urlstations = [];

const mongoData = () => {
    let res = new Promise( (resolve, reject ) => {
        MongoClient.connect(mongoConnection, ( err, connection ) => {
            if( err ){
                console.log(err.message)
                return reject(err);
            }
            let db = connection.db('atlas');
            let query = { "Status": 1 };
            let mysort = { "Broadcast": 1 };
            db.collection("stations").find(query).limit(10).sort(mysort).toArray( ( err, result ) => {
                if ( err ) throw err;
                result.map( ( obj ) => {
                    urlstations.push({'_id': `${obj._id}`, 'url':`${obj.Broadcast}`, 'location': `${obj.Name} ${obj.Module} (${obj.Frequency}) ${obj.uf} | ${obj.cityName}`});
                });
            resolve(urlstations);
            connection.close();
            });
        });
    });
    return res;
};

После этого я очищаю все свои URL, получая только HTTP или HTTPS, и очищаю все после порта.

const jsonEdit = ( result ) => {
    let res = new Promise( ( resolve, reject ) => {
        result.map( ( obj, i ) => {
            let string = JSON.stringify( obj.url );
            if( string.includes('http') ){
                let prefix = obj.url.split('//')[0];
                let cleanString = obj.url.replace(/https?:\/\//gi, '');
                urlstations[i].url = prefix + '//' + cleanString.split('/')[0];
            } else {
                delete urlstations[i];
            };
        });
        resolve(urlstations);
    })
    return res;
};

До этого момента все работало, как ожидалось, теперь у меня есть реальная проблема:

Я использую map для обхода моего массива (urlstations) и получения URL-адреса свойства из объекта с помощью пакета Request-Promise npm, чтобы попасть на страницу в Интернете, получить информацию XML и обновить мой массив urlstations, но если вы видите моя "основная" функция ниже, у меня есть console.log () после моей карты, и она ВСЕГДА печатает старый массив вместо нового.

const createUrl = ( urlstations ) => {
    let res = new Promise( ( resolve, reject ) => {
        urlstations.map( ( obj, i ) => {
            rp(obj.url + '/stats').then( ( xml ) => {
                const $ = cheerio.load( xml, {
                    xmlMode: true
                });
                urlstations[i].url = obj.url + '/stats';
                urlstations[i].uniquelisteners = `'${$('UNIQUELISTENERS').text()}'`;
                urlstations[i].averagetime = `'${$('AVERAGETIME').text()}'`;
                urlstations[i].servergenre = `'${$('SERVERGENRE').text()}'`;
                urlstations[i].serverurl = `'${$('SERVERURL').text()}'`;
                urlstations[i].songtitle = `'${$('SONGTITLE').text()}'`;
                urlstations[i].streamhits = `'${$('STREAMHITS').text()}'`;
                urlstations[i].streamuptime = `'${$('STREAMUPTIME').text()}'`;
                console.log(urlstations[i])
            }).catch( ( err ) => {
                axios.get( obj.url + '/status-json.xsl').then( ( json ) => {
                    const $ = cheerio.load( json );
                    urlstations[i].url = obj.url + '/status-json.xsl';
                    urlstations[i].genre = `'${json.data.icestats.source.genre}'`;
                    urlstations[i].listeners = `'${json.data.icestats.source.listeners}'`;
                    urlstations[i].server_url = `'${json.data.icestats.source.server_url}'`;
                    urlstations[i].listenurl = `'${json.data.icestats.source.listenurl}'`;
                    console.log(urlstations[i]);
                }).catch( ( err ) => {

                })
            });
            console.log(i)
            if( urlstations[i+1] == undefined){
                resolve(urlstations)
            }
        });
    });
    return res;
};



const master = async () => {
    let result = await mongoData();
    result = await jsonEdit(result);
    result = await createUrl(result);
    await console.log(urlstations)
}

master();

Что за массив у меня при переходе в Монго:

{ _id: '6464',
  url: 'http://01.bitstreaming.info:8240/stream',
  location: 'Itabaianinha FM (104.9) SE | Itabaianinha' },
{ _id: '3400',
  url: 'http://01.bitstreaming.info:8304/stream',
  location: 'Princesa FM (105.9) CE | Sobral' },
{ _id: '7780',
  url: 'http://01.bitstreaming.info:8334/;stream.mp3',
  location: 'Kompleta FM (96.7) GO | Jussara' }

Как я ожидаю, что эта последняя консоль покажет мне:

{ _id: '3400',
  url: 'http://01.bitstreaming.info:8304/stats',
  location: 'Princesa FM (105.9) CE | Sobral',
  uniquelisteners: '\'4\'',
  averagetime: '\'3943\'',
  servergenre: '\'Various\'',
  serverurl: '\'http://www.radiofmprincesa.com\'',
  songtitle: '\'O sucesso comeca aqui!\'',
  streamhits: '\'311354\'',
  streamuptime: '\'57178\'' }
{ _id: '7780',
  url: 'http://01.bitstreaming.info:8334/stats',
  location: 'Kompleta FM (96.7) GO | Jussara',
  uniquelisteners: '\'6\'',
  averagetime: '\'1886\'',
  servergenre: '\'Various\'',
  serverurl: '\'http://www.kompletafm.net\'',
  songtitle: '\'\'',
  streamhits: '\'174277\'',
  streamuptime: '\'57168\'' }

Я пробовал с Promise.all (https://flaviocopes.com/javascript-async-await-array-map/), но безуспешно. И другие попытки, около 2 или 3 дня, работающие над этим.

Ответы [ 2 ]

0 голосов
/ 18 апреля 2019

map не обновляет ваш существующий массив, он возвращает новый, который вы должны присвоить переменной. вы также можете использовать promise.all и возвращать новый объект в функцию карты вместо попытки изменить массив внутри цикла

попробуйте вместо этого

const createUrl = (urlstations) => {
  return Promise.all(
    urlstations.map((obj, i) => {
      return rp(obj.url + '/stats').then((xml) => {
        const $ = cheerio.load(xml, {
          xmlMode: true
        })
        return {
          url: obj.url + '/stats',
          uniquelisteners: `'${$('UNIQUELISTENERS').text()}'`,
          averagetime: `'${$('AVERAGETIME').text()}'`,
          servergenre: `'${$('SERVERGENRE').text()}'`,
          serverurl: `'${$('SERVERURL').text()}'`,
          songtitle: `'${$('SONGTITLE').text()}'`,
          streamhits: `'${$('STREAMHITS').text()}'`,
          streamuptime: `'${$('STREAMUPTIME').text()}'`
        }
      }).catch((err) => {
        return axios.get(obj.url + '/status-json.xsl').then((json) => {
          const $ = cheerio.load(json)
          return {
            url: obj.url + '/status-json.xsl',

            genre: `'${json.data.icestats.source.genre}'`,

            listeners: `'${json.data.icestats.source.listeners}'`,

            server_url: `'${json.data.icestats.source.server_url}'`,

            listenurl: `'${json.data.icestats.source.listenurl}'`
          }
        })
      })
    })
  )
}

0 голосов
/ 18 апреля 2019

Не создавайте новых Обещаний, если вам это не нужно.Просто используйте обещания, которые уже есть, и объедините их:

 const createUrl = urlstations => {
   // Just return the promise chain:
   // and use Promise.all to wait for all requests to complete
   return Promise.all(urlstations.map(async (obj, i) => { // using async / await here helps cleaning up the code

    try {
      const xml = await rp(obj.url + '/stats');
      const $ = cheerio.load( xml, {
         xmlMode: true
      });

      Object.assign(obj, { // although not related to the problem, I prefer this as it removes some repetetive accessors
        url: obj.url + '/stats',
        uniquelisteners: `'${$('UNIQUELISTENERS').text()}'`,
        averagetime: `'${$('AVERAGETIME').text()}'`,
        servergenre: `'${$('SERVERGENRE').text()}'`,
        serverurl: `'${$('SERVERURL').text()}'`,
        songtitle: `'${$('SONGTITLE').text()}'`,
        streamhits: `'${$('STREAMHITS').text()}'`,
        streamuptime: `'${$('STREAMUPTIME').text()}'`,
      });
    } catch(error) {
       //...
    }
  })).then(() => urlstations); // the returned result is the urlstations array
 };
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...