如何使用两个 map 函数进行两次提取 url
How to use two map function with two fetching url
我有两个 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 object。 children 数组转 'children: Promise {: Array(11)}'
fullfilled 这里是什么意思?因为我的代码由于这个原因无法正常工作。
我也想分享我的代码
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() 来等待所有的承诺都实现而不是让我正确 array.But 我失败了
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()
。然后你必须做同样的事情,因为 .json()
在 fetch 中(它会更干净,例如 axios
或类似的更高级别的库而不是 fetch
),一旦你有类别和 childrenData你只需要按照你想要的方式映射它。你可以通过做例如让它更简洁一点改为:
const categories = await fetch(
"https://challenge.fnaghshin.com/api/cat"
).then((res) => res.json());
尽管在我看来它的可读性较差。您可能还应该做一些错误处理,例如try/catch.
Promise.all()
需要一组 promise,但您 return 是一组对象。 promise 嵌套在对象的 children
属性中。所以我们需要做的是映射这些对象和 return 嵌套的 prop children
并将其提供给 Promise.all()
我在第二个 then
块中添加了一个异步函数,因此我可以将 await
与 Promise.all()
一起使用。这导致代码的执行要等到所有承诺,即所有 children
都已解决。之后我可以简单地 return 结果。
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()
.
会更快
这是基于承诺的版本。我把主要功能分成几个部分,这样更容易阅读。
请注意,因为您正在向 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)
我有两个 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 object。 children 数组转 'children: Promise {: Array(11)}' fullfilled 这里是什么意思?因为我的代码由于这个原因无法正常工作。 我也想分享我的代码
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() 来等待所有的承诺都实现而不是让我正确 array.But 我失败了
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()
。然后你必须做同样的事情,因为 .json()
在 fetch 中(它会更干净,例如 axios
或类似的更高级别的库而不是 fetch
),一旦你有类别和 childrenData你只需要按照你想要的方式映射它。你可以通过做例如让它更简洁一点改为:
const categories = await fetch(
"https://challenge.fnaghshin.com/api/cat"
).then((res) => res.json());
尽管在我看来它的可读性较差。您可能还应该做一些错误处理,例如try/catch.
Promise.all()
需要一组 promise,但您 return 是一组对象。 promise 嵌套在对象的 children
属性中。所以我们需要做的是映射这些对象和 return 嵌套的 prop children
并将其提供给 Promise.all()
我在第二个 then
块中添加了一个异步函数,因此我可以将 await
与 Promise.all()
一起使用。这导致代码的执行要等到所有承诺,即所有 children
都已解决。之后我可以简单地 return 结果。
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()
.
这是基于承诺的版本。我把主要功能分成几个部分,这样更容易阅读。
请注意,因为您正在向 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)