Home > database >  How to recursive Promises in a loop and passing argument to another
How to recursive Promises in a loop and passing argument to another

Time:12-29

I've checked other threads on SO but none really answers the questions as each answer ommiting something necessary for my case, and none of it is for Apple Music. Apple API is heavily promise-based and even async/await returns promise instead of response:( I am trying to get all mine playlists, but Apple imposes offset limit of 25 so I have to do this in batches. Currently I ended with something like this:

 async function getAllP() {
  let totalresult =[];
    window.music.api.music("/v1/me/library/playlists").then(function(o){
        let re = o.data;
        totalresult.push(re.data);
        if ("next" in re) {
          // what to insert here?
        } else {
          return totalresult;
        }
    });
 }

after many failed attempts to properly creates promises in loop or chaining them. I know I need some recursive function. if the keyword "next" is present in response data, then value of this key is url to fetch another batch of playlist so I need to pass that url to another promise.But I cannot set explicit .then chaining because I don't know how long that chain will be. In my case there is 80 playlists but other users may have different number so what I am struggling with is how to write loop/recursive internal function with proper argument passing to get totalresult at the end and without pyramid of doom totalresult is an 'upper' variable designed to store all the responses objects.

Update: for those who wanted how response data looks like (copied from console)


getAllPlaylist()
Promise { <state>: "fulfilled", <value>: undefined }

music.api.music('/v1/me/library/playlists')
Promise { <state>: "pending" }
​
<state>: "fulfilled"
​
<value>: Object { request: {…}, response: Response, data: {…} }
​​
data: Object { next: "/v1/me/library/playlists?offset=25", data: (25) […], meta: {…} }
​​​
data: Array(25) [ {…}, {…}, {…}, … ]
​​​
meta: Object { total: 80 }
​​​
next: "/v1/me/library/playlists?offset=25"
​​​
<prototype>: Object { … }
​​
request: Object { baseUrl: "https://api.music.apple.com", path: "/v1/me/library/playlists", url: "https://api.music.apple.com/v1/me/library/playlists", … }
​​
response: Response { type: "cors", url: "https://api.music.apple.com/v1/me/library/playlists", redirected: false, … }
​​
<prototype>: Object { … }
​
<prototype>: Promise.prototype { … }

music.api.music('/v1/me/library/playlists?offset=25')
Promise { <state>: "pending" }

CodePudding user response:

Hope this will solve your issue,

const getAll = async () => {
  const totalResult = [];
  const getP = async (url) => {
    const { data } = await window.music.api.music(url);
    const hasMore = "next" in data;
    totalResult.push(...data);
    if (hasMore) return getP(data.next.url);
  };
  const url = "/v1/me/library/tracks";
  await getP(url);
  return totalResult;
};

CodePudding user response:

I am not sure how the response data looks like. I guess you are looking something like below:

Note: you may handle error yourself.

async function getAllP() {
    const totalresult = [];
    let url = "/v1/me/library/playlists";
    while (true) {
        const o = await window.music.api.music(url);
        const re = o.data;
        totalresult.push(re.data);
        if ("next" in re) {
            url = re.next.url; // assume there is a url in the next.
            continue;
        }

        break;
    }

    return totalresult;
}
  • Related