Javascript 链接映射的axios/API调用

Javascript 链接映射的axios/API调用,javascript,node.js,axios,spotify,Javascript,Node.js,Axios,Spotify,对于我正在使用的API,我必须从3个独立的端点反弹才能获得所需的数据。我被困在最后一个终点,这让我发疯。以下是我目前正在做(或试图做)的要点 直接调用端点1。通过map处理数据(返回我特别需要的数据),然后推送到ARRAY 1 处理完数组1后,我将数组1的数据映射到端点2,为每个ID调用API,然后将其推送到数组2 一旦处理完数组2,我就将数组2的数据映射到端点3,为它的每个ID进行API调用,然后将其推送到数组3 所有这些步骤都包含在一个承诺中,该承诺使用3个完整的数组进行解析 第1步和第2步

对于我正在使用的API,我必须从3个独立的端点反弹才能获得所需的数据。我被困在最后一个终点,这让我发疯。以下是我目前正在做(或试图做)的要点

  • 直接调用端点1。通过map处理数据(返回我特别需要的数据),然后推送到ARRAY 1
  • 处理完数组1后,我将数组1的数据映射到端点2,为每个ID调用API,然后将其推送到数组2
  • 一旦处理完数组2,我就将数组2的数据映射到端点3,为它的每个ID进行API调用,然后将其推送到数组3
  • 所有这些步骤都包含在一个承诺中,该承诺使用3个完整的数组进行解析
  • 第1步和第2步做得很好,但我在第3步中尝试了一百万种不同的方法,它不断返回。处理这个问题的最佳方式是什么?任何帮助都将不胜感激

    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()和新的承诺等,它会变得非常混乱,非常快

    我已经这样重组了,我认为这更容易遵循,希望能够调试

    我们可以循环getXXX函数中的每一项,也可以使用Promise.all,这两种方法都有效,尽管后者可能更有效

    我在getTracks()中使用了这个

    router.get(“/”,异步(req,res)=>{
    让选项={
    标题:{
    'Authorization':'Bearer${token}`,
    }
    }
    如果(!令牌){
    res.send({
    消息:“请登录以检索数据”,
    });
    返回;
    }
    常量url=https://api.spotify.com/v1/me/following?type=artist&limit=50';
    让艺术家=等待getArtists(url,选项);
    console.log(“艺术家(长度):”,艺术家.length);
    let albums=Wait getAlbums(艺术家、选项);
    console.log(“相册(长度):”,Albums.length);
    let tracks=等待获取(相册、选项);
    log(“Tracks(length):”,Tracks.length);
    res.send({专辑、艺术家、曲目});
    }
    异步函数getArtists(url、选项、maxLoopCount=100){
    让艺术家=[];
    让计数=0;
    做{
    log(`getArtists:Page#${++count}…`);
    让artistResp=等待getArtistsPage(url,选项);
    艺术家。推手(…艺术家;艺术家);
    url=artistResp.next;
    }while(url&&count({
    url:artist.external_url.spotify,
    姓名:艺人姓名,
    图片:艺术家图片,
    id:artist.id,
    类型:艺术家。类型,
    }));
    让next=response.data.artists.next;
    返回{artistList,next}
    };
    异步函数getAlbums(艺术家、选项、切片计数=50){
    让相册=[];
    为了(让艺术家成为艺术家中的艺术家){
    let response=等待axios.get(`https://api.spotify.com/v1/artists/${artist.id}/albums?market=us&include\u groups=single,出现在`,选项);
    相册。推送(…响应。数据。项);
    }
    const filtered=albums.filter((curr,index,self)=>self.findIndex(t=>t.id==curr.id)==index);
    const sorted=filtered.sort((a,b)=>(b.release\u date>a.release\u date)?1:-1);//将数据更改为filtered以过滤重复项
    const sliced=sorted.slice(0,sliceCount);
    返回切片;
    }
    异步函数(相册、选项){
    让承诺=albums.map(album=>axios.get(`https://api.spotify.com/v1/albums/${album.id}/tracks`,options));
    让响应列表=等待承诺。全部(承诺);
    返回responseList.map(response=>response.data.items.flat();
    }
    
    我认为您最好采用一种更简单的方法,使用async/await。这使我们能够以一种更容易理解的方式构造代码。如果我们有大量的.then()和新承诺等,它会很快变得非常混乱

    我已经这样重组了,我认为这更容易遵循,希望能够调试

    我们可以循环getXXX函数中的每一项,也可以使用Promise.all,这两种方法都有效,尽管后者可能更有效

    我在getTracks()中使用了这个

    router.get(“/”,异步(req,res)=>{
    让选项={
    标题:{
    'Authorization':'Bearer${token}`,
    }
    }
    如果(!令牌){
    res.send({
    消息:“请登录以检索数据”,
    });
    返回;
    }
    常量url=https://api.spotify.com/v1/me/following?type=artist&limit=50';
    让艺术家=等待getArtists(url,选项);
    console.log(“艺术家(长度):”,艺术家.length);
    let albums=Wait getAlbums(艺术家、选项);
    console.log(“相册(长度):”,Albums.length);
    let tracks=等待获取(相册、选项);
    log(“Tracks(length):”,Tracks.length);
    res.send({专辑、艺术家、曲目});
    }
    异步函数getArtists(url、选项、maxLoopCount=100){
    让艺术家=[];
    让计数=0;
    做{
    log(`getArtists:Page#${++count}…`);
    让artistResp=等待getArtistsPage(url,选项);
    艺术家。推手(…艺术家;艺术家);
    url=artistResp.next;
    }while(url&&count({
    url:artist.external_url.spotify,
    姓名:艺人姓名,
    图片:艺术家图片,
    id:artist.id,
    类型:艺术家。类型,
    }));
    让next=response.data.artists.next;
    返回{artistList,next}
    };
    异步函数getAlbums(艺术家、选项、切片计数=50){
    让相册=[];
    
    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();
    }