链接映射 axios/API 调用
Chaining mapped axios/API calls
对于我正在使用的 API,我必须从 3 个单独的端点反弹才能获得我需要的数据。我被困在最后一个终点,这让我发疯。这是我目前正在做(或试图做)的要点。
- 直接调用ENDPOINT 1。通过map处理数据(到return我具体需要的数据)然后推送到ARRAY 1。
- ARRAY 1 完成处理后,我将映射 ARRAY 1 的数据以对其每个 ID 进行 API 调用到 ENDPOINT 2,然后将其推送到 ARRAY 2。
- ARRAY 2 完成处理后,我将映射 ARRAY 2 的数据以对其每个 ID 进行 API 调用到 ENDPOINT 3,然后将其推送到 ARRAY 3。
- 所有这些步骤都包含在一个 promise 中,该 promise 用 3 个完整的数组解析。
第 1 步和第 2 步做得很好,但我已经为第 3 步尝试了一百万种不同的方法,并且它保持 returning 。处理此问题的最佳方法是什么?任何帮助将不胜感激!
router.get("/", (req, res) => {
let artists = [];
let albums = [];
let tracks = [];
const options = {
headers: {
'Authorization': `Bearer ${token}`,
},
};
function getArtists(url) {
return new Promise(resolve => {
axios.get(url, options).then(response => {
artists.push(...response.data.artists.items.map(artist => ({
url: artist.external_urls.spotify,
name: artist.name,
images: artist.images,
id: artist.id,
genres: artist.genres,
})));
let next = response.data.artists.next;
if (next !== null) {
getArtists(next);
} else {
resolve(getAlbums().then(() => getTracks().then(() => res.send({artists, albums, tracks}))));
};
});
});
};
let getAlbums = () => {
return new Promise(resolve => {
const requests = artists.map(item => {
return axios.get(`https://api.spotify.com/v1/artists/${item.id}/albums?market=us&include_groups=single,appears_on`, options).then(response => {
albums.push(...response.data.items);
});
});
Promise.all(requests).then(() => {
const filtered = albums.filter((curr, index, self) => self.findIndex(t => t.id === curr.id) === index);
const sorted = filtered.sort((a, b) => (b.release_date > a.release_date) ? 1 : -1); // change data to filtered to filter duplicates
const sliced = sorted.slice(0, 50);
albums = sliced;
// res.send({artists, albums});
resolve();
});
});
};
let getTracks = () => {
albums.map(item => {
return axios.get(`https://api.spotify.com/v1/albums/${item.id}/tracks`, options).then(response => {
tracks.push(...response.data.items);
});
});
};
if (token) {
const url = 'https://api.spotify.com/v1/me/following?type=artist&limit=50';
getArtists(url);
} else {
res.send({
message: 'Please login to retrieve data',
});
};
});
我认为您最好采用更简单的方法,使用 async/await。这使我们能够以更易于遵循的方式构建代码。如果我们有大量的 .then() 和新的 Promises 等,它会很快变得非常混乱!
我已经像这样重组了,我认为这更容易理解并且希望能够调试!
我们可以遍历 getXXX 函数中的每个项目,或者我们可以使用 Promise.all,这两种方法都有效,尽管后者可能更高效。
我在 getTracks() 中使用过这个
router.get("/", async (req, res) => {
let options = {
headers: {
'Authorization': `Bearer ${token}`,
}
}
if (!token) {
res.send({
message: 'Please login to retrieve data',
});
return;
}
const url = 'https://api.spotify.com/v1/me/following?type=artist&limit=50';
let artists = await getArtists(url, options);
console.log ("Artists (length):", artists.length );
let albums = await getAlbums(artists, options);
console.log ("Albums (length):", albums.length );
let tracks = await getTracks(albums, options);
console.log("Tracks (length):", tracks.length);
res.send( { albums, artists, tracks } );
}
async function getArtists(url, options, maxLoopCount = 100) {
let artists = [];
let count = 0;
do {
console.log(`getArtists: Page #${++count}...`);
let artistResp = await getArtistsPage(url, options);
artists.push(...artistResp.artistList);
url = artistResp.next;
} while (url && count < maxLoopCount) ;
return artists;
}
async function getArtistsPage(url, options) {
let response = await axios.get(url, options);
let artistList = response.data.artists.items.map(artist => ({
url: artist.external_urls.spotify,
name: artist.name,
images: artist.images,
id: artist.id,
genres: artist.genres,
}));
let next = response.data.artists.next;
return { artistList, next}
};
async function getAlbums(artists, options, sliceCount = 50) {
let albums = [];
for(let artist of artists) {
let response = await axios.get(`https://api.spotify.com/v1/artists/${artist.id}/albums?market=us&include_groups=single,appears_on`, options);
albums.push(...response.data.items);
}
const filtered = albums.filter((curr, index, self) => self.findIndex(t => t.id === curr.id) === index);
const sorted = filtered.sort((a, b) => (b.release_date > a.release_date) ? 1 : -1); // change data to filtered to filter duplicates
const sliced = sorted.slice(0, sliceCount);
return sliced;
}
async function getTracks(albums, options) {
let promises = albums.map(album => axios.get(`https://api.spotify.com/v1/albums/${album.id}/tracks`, options));
let responseList = await Promise.all(promises);
return responseList.map(response => response.data.items).flat();
}
对于我正在使用的 API,我必须从 3 个单独的端点反弹才能获得我需要的数据。我被困在最后一个终点,这让我发疯。这是我目前正在做(或试图做)的要点。
- 直接调用ENDPOINT 1。通过map处理数据(到return我具体需要的数据)然后推送到ARRAY 1。
- ARRAY 1 完成处理后,我将映射 ARRAY 1 的数据以对其每个 ID 进行 API 调用到 ENDPOINT 2,然后将其推送到 ARRAY 2。
- ARRAY 2 完成处理后,我将映射 ARRAY 2 的数据以对其每个 ID 进行 API 调用到 ENDPOINT 3,然后将其推送到 ARRAY 3。
- 所有这些步骤都包含在一个 promise 中,该 promise 用 3 个完整的数组解析。
第 1 步和第 2 步做得很好,但我已经为第 3 步尝试了一百万种不同的方法,并且它保持 returning 。处理此问题的最佳方法是什么?任何帮助将不胜感激!
router.get("/", (req, res) => {
let artists = [];
let albums = [];
let tracks = [];
const options = {
headers: {
'Authorization': `Bearer ${token}`,
},
};
function getArtists(url) {
return new Promise(resolve => {
axios.get(url, options).then(response => {
artists.push(...response.data.artists.items.map(artist => ({
url: artist.external_urls.spotify,
name: artist.name,
images: artist.images,
id: artist.id,
genres: artist.genres,
})));
let next = response.data.artists.next;
if (next !== null) {
getArtists(next);
} else {
resolve(getAlbums().then(() => getTracks().then(() => res.send({artists, albums, tracks}))));
};
});
});
};
let getAlbums = () => {
return new Promise(resolve => {
const requests = artists.map(item => {
return axios.get(`https://api.spotify.com/v1/artists/${item.id}/albums?market=us&include_groups=single,appears_on`, options).then(response => {
albums.push(...response.data.items);
});
});
Promise.all(requests).then(() => {
const filtered = albums.filter((curr, index, self) => self.findIndex(t => t.id === curr.id) === index);
const sorted = filtered.sort((a, b) => (b.release_date > a.release_date) ? 1 : -1); // change data to filtered to filter duplicates
const sliced = sorted.slice(0, 50);
albums = sliced;
// res.send({artists, albums});
resolve();
});
});
};
let getTracks = () => {
albums.map(item => {
return axios.get(`https://api.spotify.com/v1/albums/${item.id}/tracks`, options).then(response => {
tracks.push(...response.data.items);
});
});
};
if (token) {
const url = 'https://api.spotify.com/v1/me/following?type=artist&limit=50';
getArtists(url);
} else {
res.send({
message: 'Please login to retrieve data',
});
};
});
我认为您最好采用更简单的方法,使用 async/await。这使我们能够以更易于遵循的方式构建代码。如果我们有大量的 .then() 和新的 Promises 等,它会很快变得非常混乱!
我已经像这样重组了,我认为这更容易理解并且希望能够调试!
我们可以遍历 getXXX 函数中的每个项目,或者我们可以使用 Promise.all,这两种方法都有效,尽管后者可能更高效。
我在 getTracks() 中使用过这个
router.get("/", async (req, res) => {
let options = {
headers: {
'Authorization': `Bearer ${token}`,
}
}
if (!token) {
res.send({
message: 'Please login to retrieve data',
});
return;
}
const url = 'https://api.spotify.com/v1/me/following?type=artist&limit=50';
let artists = await getArtists(url, options);
console.log ("Artists (length):", artists.length );
let albums = await getAlbums(artists, options);
console.log ("Albums (length):", albums.length );
let tracks = await getTracks(albums, options);
console.log("Tracks (length):", tracks.length);
res.send( { albums, artists, tracks } );
}
async function getArtists(url, options, maxLoopCount = 100) {
let artists = [];
let count = 0;
do {
console.log(`getArtists: Page #${++count}...`);
let artistResp = await getArtistsPage(url, options);
artists.push(...artistResp.artistList);
url = artistResp.next;
} while (url && count < maxLoopCount) ;
return artists;
}
async function getArtistsPage(url, options) {
let response = await axios.get(url, options);
let artistList = response.data.artists.items.map(artist => ({
url: artist.external_urls.spotify,
name: artist.name,
images: artist.images,
id: artist.id,
genres: artist.genres,
}));
let next = response.data.artists.next;
return { artistList, next}
};
async function getAlbums(artists, options, sliceCount = 50) {
let albums = [];
for(let artist of artists) {
let response = await axios.get(`https://api.spotify.com/v1/artists/${artist.id}/albums?market=us&include_groups=single,appears_on`, options);
albums.push(...response.data.items);
}
const filtered = albums.filter((curr, index, self) => self.findIndex(t => t.id === curr.id) === index);
const sorted = filtered.sort((a, b) => (b.release_date > a.release_date) ? 1 : -1); // change data to filtered to filter duplicates
const sliced = sorted.slice(0, sliceCount);
return sliced;
}
async function getTracks(albums, options) {
let promises = albums.map(album => axios.get(`https://api.spotify.com/v1/albums/${album.id}/tracks`, options));
let responseList = await Promise.all(promises);
return responseList.map(response => response.data.items).flat();
}