Как мне реализовать обратный вызов / ожидание моего кода? - PullRequest
0 голосов
/ 28 сентября 2018

Итак, я работал над этим кодом последние несколько дней и пытался реализовать callback / await / все, что нужно, но безрезультатно.

Вопрос в том, как мне ждать ответа, пока не получим, скажем, обратный вызов от обеих функций?(и как бы я это реализовал)

Короче, я хочу сделать следующее:

  1. POST происходит, getpTracks()
  2. С getpTracks() мы идемна dbChecks() для каждого трека, который мы получили
  3. Проверьте из db, если трек найден, если он выдвигается в конечный массив.
  4. Если нет, перейдите к scrapeUrl()
  5. После того, как обе функции будут запущены, ответьте на POST с окончательным массивом.

Я объединил код с какой-то прикольной проверкой кода каждые 250 мс, если количество запрошенных треков совпадает с количествомтреки в окончательном массиве.Но на самом деле это не то, что я ищу, поскольку, если есть более одного запроса POST за раз, он действительно прерывается.

Текущий код:

app.post("/spotify/playlist", (req, res) => {
  pTracks = [];
  let playlistId = req.body.id;
  t0 = performance.now();
  getpTracks(playlistId);
  let waitTime = setInterval(waitTillReady, 250);
  function waitTillReady() {
    counterLoop++;
    console.log("a: " + countera + "||" + pTracks.length);
    console.log("b: " + counterb + "||" + pTracks.length);
    console.log("a + b: " + (countera + counterb) + "||" + pTracks.length);
    console.log("Loop: " + counterLoop);
    // REPLACE WITH ASYNC OR CALLBACK!!
    if (
      countera == pTracks.length ||
      counterb == pTracks.length ||
      countera + counterb == pTracks.length ||
      counterLoop == 35 // 75 items scraping took on avg 4.8sec
    ) {
      countera = 0;
      counterb = 0;
      clearInterval(waitTime);
      res.send(pTracks);
      t1 = performance.now();
      console.log("Call took " + (t1 - t0) + " milliseconds.");
      pTracks = [];
    }
  }
});
function getpTracks(args) {
  spotifyApi.getPlaylistTracks(args, { limit: 75 }).then(function(data) {
    let temp = data.body.items;
    for (let b = 0; b < temp.length; b++) {
      let trackName = temp[b].track.name;
      for (let e = 0; e < temp[b].track.artists.length; e++) {
        var trackArtist = temp[b].track.artists[e].name;
      }
      dbChecks(trackName, trackArtist);
      //let trackId = temp[b].track.id + ",";
      //spotifyApi.getAudioFeaturesForTracks([trackId]).then(function(data) { // bpm, key etc
    }
  });
}
function dbChecks(trackName, trackArtist) {
  url = "https://www.songsterr.com/a/wa/bestMatchForQueryString?s=";
  //console.log(trackArtist + '|||' + trackName);
  //console.log(url)
  dbSongsterr
    .findOne({ artist: trackArtist, track: trackName }) // get results from mongo
    .then(response => {
      if (
        //if we find results,
        response != null &&
        response.artist == trackArtist &&
        response.track == trackName
      ) {
        countera++;
        pTracks.push({
          //push them into array
          artist: response.artist,
          name: response.track,
          url: response.url,
          tuning: response.tuning
        });
      } else if (response == null) {
        //if no results found, go webscrape
        urli = url + trackName + "&a=" + trackArtist; // url constructor
        pTracks.push({
          artist: trackArtist,
          name: trackName,
          url: urli
        });
        scrapeUrl(urli, trackName, trackArtist);
      }
    })
    .catch(error => {
      console.log("Error: " + error);
    });
}
function scrapeUrl(url, track, artist) {
  url = url;
  console.log(artist + "|||" + track);
  rp({
    url: url,
    resolveWithFullResponse: true,
    transform: function(body) {
      return cheerio.load(body);
    }
  })
    .then(async res => {
      counterb++;
      tempartist = artist.replace(/\s+/g, "");
      artistSongsterr = await res(".artist-1u304B") // tab page artist name
        .text()
        .replace(/\s+/g, "");
      //console.log(artistSongsterr);
      if (
        artistSongsterr != "" &&
        artistSongsterr.toLowerCase() == tempartist.toLowerCase()
      ) {
        // maybe add check for song aswell
        tuning = res(".tuning-1cQdvc").text(); // tab page tuning
        //console.log(tuning);
        if (tuning != "") {
          for (let y = 0; y < pTracks.length; y++) {
            if (pTracks[y].name == track && pTracks[y].tuning == null) {
              pTracks[y] = { ...pTracks[y], ...{ tuning: tuning } };
              dbSongsterr.insert({
                artist: artist,
                track: track,
                url: url,
                tuning: tuning
              });
            }
          }
        }
      } else {
        dbSongsterr.insert({
          // if didnt pass artist name check then
          artist: artist,
          track: track,
          url: false,
          tuning: false
        });
        //console.log('Artist check fail')
      }
    })
    .catch(err => {
      counterb++;
      console.log("Site crawl fail");
      pTracks.push({
        artist: track,
        name: track,
        url: false,
        tuning: false
      });
      dbSongsterr.insert({
        artist: artist,
        track: track,
        url: false,
        tuning: false
      });
    });
}

1 Ответ

0 голосов
/ 28 сентября 2018

Несколько общих советов:

  • Обычно вам никогда не нужны глобальные переменные (поэтому объявляйте их правильно), функции должны возвращать результаты, которые они производят, если переменные, переданные между несколькими функциями, передают их явно.

  • Не смешивайте .then цепочки с await s, это выглядит некрасиво, сбивает с толку и может привести к незначительным ошибкам.

При этом ваши функции должны быть асинхронными:

async function scrapeUrl(url, track, artist, result = []) {
  console.log(artist + "|||" + track);

  try {

   const res = await rp({
    url,
    resolveWithFullResponse: true,
    transform: function(body) {
      return cheerio.load(body);
    },
   });

   const tempartist = artist.replace(/\s+/g, "");
   const artistSongsterr = await res(".artist-1u304B") // tab page artist name
          .text()
          .replace(/\s+/g, "");

      if (artistSongsterr  && artistSongsterr.toLowerCase() == tempartist.toLowerCase()) {
        // maybe add check for song aswell
        const tuning = res(".tuning-1cQdvc").text(); // tab page tuning

        if (tuning) {
          for (const el of pTracks) {
            if (el.name == track && !el.tuning) {
              el.tuning = tuning;

              result.push({ url, track, artist, tuning });
            }
          }
        }
      } else {
        result.push({
          // if didnt pass artist name check then
          artist,
          track,
          url: false,
          tuning: false
        });
        //console.log('Artist check fail')
      }
    }
   } catch(error) {
      console.log("Site crawl fail");
      result.push({
        artist: track,
        name: track,
        url: false,
        tuning: false
      });

   }

   return result;
}


async function dbChecks(trackName, trackArtist, result = []) {
  const url = "https://www.songsterr.com/a/wa/bestMatchForQueryString?s=";

  try {
    const response = await dbSongsterr
      .findOne({ artist: trackArtist, track: trackName }) // get results from mongo

    if (
      //if we find results,
      response &&
      response.artist == trackArtist &&
      response.track == trackName
    ) {

      result.push({
        //push them into array
        artist: response.artist,
        name: response.track,
        url: response.url,
        tuning: response.tuning
      });
  } else {
    //if no results found, go webscrape
    const urli = url + trackName + "&a=" + trackArtist; // url constructor
    result.push({
      artist: trackArtist,
      name: trackName,
      url: urli
    });
    await scrapeUrl(urli, trackName, trackArtist, result);
  }
 } catch(error) {
  console.log("Error: " + error);
 }

 return result;
}


async function getpTracks(args) {
  const result = [];

  const data = await spotifyApi.getPlaylistTracks(args, { limit: 75 });
  let temp = data.body.items;

  for (const { track: { name: trackName, artists  }} of  temp) {

    const trackArtist = artists[artists.length - 1].name;
    // TODO: use Promise.all to parallelize
    await dbChecks(trackName, trackArtist, result);

  }

  return result;
}

Это может быть использовано в конечной точке как:

app.post("/spotify/playlist", async (req, res) => {
  res.send(await getpTracks(req.body.id));
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...