因此,过去几天来我一直在研究此代码,并尝试实现回调/等待/任何无济于事的方法。
问题是,我该如何等待响应,直到让我说出两个函数的回调? (以及我将如何实现)
简而言之,我想做的是:
getpTracks()
getpTracks()
开始,我们进入的每个曲目都dbChecks()
scrapeUrl()
如果请求的磁道数量与最终数组中的磁道数量匹配,我每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
});
});
}
答案 0 :(得分:1)
一些一般建议:
您通常不需要全局变量(因此正确声明它们),如果变量应在多个函数之间共享,则函数应返回它们产生的结果。
不要将.then
链与await
混合使用,这看起来很丑陋,令人困惑,并且可能会引入细微的错误。
这表示您的功能应该是异步的:
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));
});