如何在循环中递归承诺并将参数传递给另一个

How to recursive Promises in a loop and passing argument to another

我已经检查了 SO 上的其他线程,但 none 确实回答了问题,因为每个答案都省略了我的案例所需的内容,其中 none 是针对 Apple Music 的。 Apple API 是基于承诺的,甚至 async/await returns 承诺而不是响应:( 我正在尝试获取我的所有播放列表,但 Apple 规定了 25 个偏移量限制,因此我必须分批执行此操作。 目前我以这样的方式结束:

 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;
        }
    });
 }

在多次尝试在循环中正确创建 promise 或链接它们失败之后。我知道我需要一些递归函数。如果响应数据中存在关键字“next”,则此键的值为 url 以获取另一批播放列表,因此我需要将 url 传递给另一个 promise.But 我无法设置显式 .then 链接,因为我不知道该链有多长。在我的例子中,有 80 个播放列表,但其他用户可能有不同的数字,所以我正在努力解决的是如何编写 loop/recursive 内部函数,并传递适当的参数以在最后获得 totalresult 并且没有厄运金字塔 totalresult 是一个 'upper' 变量,用于存储所有响应对象。

更新: 对于那些想要响应数据的样子(从控制台复制)的人


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" }

解决方案:

我不确定响应数据的样子。 我猜你看起来像下面这样:

注意:您可以自己处理错误。

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;
}

希望这能解决您的问题,

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;
};

You can do while(url) and url = re.next.url without ifs and continues and breaks.

@Thomas since when it's possible to write like that? isn't that confusing to read?

async function getAllP() {
  const totalresult = [];

  let url = "/v1/me/library/playlists";
  while (url) {
    const { data } = await window.music.api.music(url);
    totalresult.push(...data.data);
    url = data.next;
  }

  return totalresult;
}

@Sebastian,这读起来很混乱吗?

虽然我有一个 url,但是...

并且 truthy and falsy 值的概念在 JS 中永远存在。