如何使用带有两个获取url的两个map函数



我有两个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数组转换为"children:Promise{:array(11)}"fullfull在这里是什么意思?因为我的代码由于这个原因无法工作。我想分享我的代码也

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都被填满,而不是将我的数组向右翻转。但我没有通过

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

所以,首先你得到你的类别,这很简单。然后,您要做的是在具有来自类别(childrenResponses)的ID的提取调用列表中使用Promise.all()。然后,由于fetch中有.json(),您必须执行同样的操作(例如,使用axios或类似的更高级别库而不是fetch,它会更干净),并且一旦您有了类别和子级数据,您只需要按您想要的方式映射它。你可以通过这样做来使它更加简洁,例如:

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

尽管在我看来它可读性较差。您可能还应该做一些错误处理,例如使用try/catch。

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

我在第二个then块中添加了一个异步函数,所以我可以将awaitPromise.all()一起使用。这会导致代码的执行等待,直到所有的promise,也就是所有的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()中使用wait,因为这会使执行持续更长时间。因为在映射的每次迭代中,它将await作为fetch()的响应,然后再进行下一次迭代并激发下一个fetch()。因此,与其一次(基本上)解雇他们,不如一个接一个地解雇他们。一次发射它们,然后等待Promise.all()会更快。

这是一个基于promise的版本。我把主要功能分成了几个部分,这样读起来更容易。

请注意,由于您正在向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)

最新更新