如何使用两个地图功能和两个获取 url

Posted

技术标签:

【中文标题】如何使用两个地图功能和两个获取 url【英文标题】:How to use two map function with two fetching url 【发布时间】:2021-11-23 10:37:13 【问题描述】:

我有两个 api 我应该把它们变成这样的数组

[
            
                key: "0",
                label: 'Installation',
                children: [
                     key: "0-0", label: 'Getting Started', url: 'https://reactjs.org/docs/getting-started.html' ,
                     key: "0-1", label: 'Add React', url: 'https://reactjs.org/docs/add-react-to-a-website.html' ,
                     key: "0-2", label: 'Create an App', url: 'https://reactjs.org/docs/create-a-new-react-app.html' ,
                     key: "0-3", label: 'CDN Links', url: 'https://reactjs.org/docs/cdn-links.html' 
                ]
            ,
            
                key: "1",
                label: 'Main Concepts',
                children: [
                     key: "1-0", label: 'Hello World', url: 'https://reactjs.org/docs/hello-world.html' ,
                     key: "1-1", label: 'Introducing JSX', url: 'https://reactjs.org/docs/introducing-jsx.html' ,
                     key: "1-2", label: 'Rendering Elements', url: 'https://reactjs.org/docs/rendering-elements.html' ,
                     key: "1-3", label: 'Components and Props', url: 'https://reactjs.org/docs/components-and-props.html' ,
                     key: "1-4", label: 'State and LifeCycle', url: 'https://reactjs.org/docs/state-and-lifecycle.html' ,
                     key: "1-5", label: 'Handling Events', url: 'https://reactjs.org/docs/handling-events.html' 
                ]
            
        ];

顺便说一句,我有两个API,其中一个获取所有类别,第二个API是获取孩子的名字。所以我创建了链式提取,但我无法正确获取子对象。 children 数组变成了“children: Promise : Array(11)” 这里的满是什么意思?因为我的代码由于这个原因而无法工作。 我也想分享我的代码

 getCategories() 
    return fetch('https://challenge.fnaghshin.com/api/cat')
      .then((res) => res.json())
      .then((d) => 
        return Promise.all(
          d.map((e) => 
            return 
              key: e.id,
              label: e.name,
              date: e.created_at,
              children: fetch(
                `https://challenge.fnaghshin.com/api/catpro/$e.id`
              )
                .then((res) => res.json())
                .then((d) =>
                  d.map((e) => 
                    return 
                      key: e.id,
                      label: e.name,
                    ;
                  )
                ),
            ;
          )
        );
      );
  

我还使用 Promise.all() 来等待所有承诺都完成,而不是向右转数组。但我失败了

【问题讨论】:

你是否在 Promise.all() 中返回一个承诺? @Invizi 不,我该怎么做? fetch() 是一个异步函数。 async 函数返回承诺。 Promise.all() 不是递归的,所以不能解决那些深层嵌套的承诺。 @Ouroborus 你能帮我解决这个深深嵌套的承诺吗? @sayinmehmet47 你可以运行我的答案,看看它是否符合你的要求。 【参考方案1】:

IMO 最干净的解决方案是使用 async/await,使用嵌套的 Promises 很快就会变得相当不可读。

async function getCategories() 
  const response = await fetch("https://challenge.fnaghshin.com/api/cat");
  const categories = await response.json();

  const childrenResponses = await Promise.all(
    categories.map((cat) =>
      fetch(`https://challenge.fnaghshin.com/api/catpro/$cat.id`)
    )
  );

  const childrenData = await Promise.all(
    childrenResponses.map((response) => response.json())
  );

  return categories.map((cat, index) => (
    key: cat.id,
    label: cat.name,
    date: cat.created_at,
    children: childrenData[index].map((child) => (
      key: child.id,
      label: child.title
    ))
  ));

所以首先你得到你的类别,这很简单。然后,您要做的是在 fetch 调用列表中使用 Promise.all(),并使用您从类别 (childrenResponses) 中获得的 ID。然后你必须做同样的事情,因为.json() in fetch(它会更干净,例如axios或类似的更高级别的库而不是fetch),一旦你有了类别和childrenData,你只需要映射它你想要的方式。您可以通过执行例如使其更简洁一些。改为:

const categories = await fetch(
  "https://challenge.fnaghshin.com/api/cat"
).then((res) => res.json());

虽然在我看来它的可读性较差。您可能还应该进行一些错误处理,例如使用 try/catch。

【讨论】:

这种用法也会报429错误。看看 ProductService.js:30 GET challenge.fnaghshin.com/api/catpro/8 429(请求太多) 这 99% 与你如何调用这个函数有关。它在隔离时工作得非常好(你甚至可以在 DevTools 控制台或其他东西中运行它)。此外,如果您到目前为止一直在通过调用向 API 发送垃圾邮件,那么您可能只是暂时被 API 阻止。等待几分钟/几小时,然后重试。【参考方案2】:

Promise.all() 需要一个承诺数组,但您返回的是一个对象数组。承诺嵌套在对象的 children 属性中。所以我们需要做的是映射这些对象并返回嵌套的 prop children 并将其提供给 Promise.all()

我在第二个then 块中添加了一个异步函数,因此我可以将awaitPromise.all() 一起使用。这会导致代码的执行要等到所有承诺,即所有children 都已解决。之后我可以简单地返回结果。

function getCategories() 
  return fetch('https://challenge.fnaghshin.com/api/cat')
    .then((res) => res.json())
    .then(async (d) => 
      const withChildren = d.map((e) => 
        return 
          key: e.id,
          label: e.name,
          date: e.created_at,
          children: fetch(`https://challenge.fnaghshin.com/api/catpro/$e.id`).then(res => res.json())
        
      )
      await Promise.all(withChildren.map(item => item.children))
      return withChildren
    )

429 (Too Many Requests) 似乎是一个速率限制,当您在特定时间内过于频繁地触发请求时。我也有。现在又没了。

PS:在这种情况下,不要在 map() 中使用 await,因为这会延长执行时间。因为在地图的每一次迭代中,它都会await 响应fetch(),然后再进行下一次迭代并触发下一次fetch()。因此,不是一次全部解雇(基本上),而是一个接一个地解雇他们。一次将它们全部触发,然后等待 Promise.all() 会更快。

【讨论】:

【参考方案3】:

这是一个基于承诺的版本。我将主要功能分成几部分,这样更容易阅读。

请注意,由于您向 API 发出了许多请求,您可能会收到 429: too many requests 警告。

要解决这个问题,您可以为每个请求使用代理,也可以检查状态代码并等待响应告诉您等待的时间。

const URL = 'https://challenge.fnaghshin.com/api/cat';
const CHILDREN_URL = `https://challenge.fnaghshin.com/api/catpro/`;

function getCategories() 
  return fetch(URL)
    .then(res => res.json())
    .then(data => Promise.all(data.map(getSubCategories)));


function getSubCategories(data) 
  return fetch(CHILDREN_URL + data.id)
    .then(res => res.json())
    .then(info => (
      key: data.id,
      label: data.name,
      date: data.created_at,
      children: info.map(e => (
        key: e.id,
        label: e.title,
      )),
    ));


getCategories()
  .then(console.log)
  .catch(console.log)

【讨论】:

以上是关于如何使用两个地图功能和两个获取 url的主要内容,如果未能解决你的问题,请参考以下文章

如何使用LatLng在谷歌地图v2中以公里为单位获取两个地方之间的距离

给定两个位置,如何从谷歌地图获取所有纬度和经度

如何使用 Klaxon 从我的 JSON 文件中的两个数组中获取第一个图像 URL?

如何在 iOS 中获取两个 json url 的数据

如何在iOS中以文本形式获取两个位置之间的路线

如何通过滑行在 Google 地图上的 infoWindow 中获取图像 - Android