JavaScript Map 内部使用 Fetch

6
我有一个展示我的项目的网站/作品集,使用Github API。我的目标是为这些项目创建一个筛选器,因此我在一些仓库的根目录中创建了一个名为“built-with.json”的文件,该文件仅存在于 两个仓库 中,仅用于测试目的。它是一个技术数组,包含我在项目中使用的所有技术(例如:["React", "Javascript",...])。因此,我需要获取Github API(该部分工作正常),然后获取该文件,并返回一个新的项目数组,但其中包含一个“filters”键,其值是“built-with.json” 中的数组。 例如:
Github API 返回(仅返回一个项目的示例):
[{
"id": 307774617,
"node_id": "MDEwOlJlcG9zaXRvcnkzMDc3NzQ2MTc=",
"name": "vanilla-javascript-utility-functions",
"full_name": "RodrigoWebDev/vanilla-javascript-utility-functions",
"private": false
}]

我需要的新对象数组:

[{
"id": 307774617,
"node_id": "MDEwOlJlcG9zaXRvcnkzMDc3NzQ2MTc=",
"name": "vanilla-javascript-utility-functions",
"full_name": "RodrigoWebDev/vanilla-javascript-utility-functions",
"private": false,
"filters": ["HTML5", "CSS3", "JS", "React"]
}]

这就是我所做的:

const url = "https://api.github.com/users/RodrigoWebDev/repos?per_page=100&sort=created";
fetch(url)
  .then((response) => response.json())
  .then((data) => {
      return data.map(item => {
        //item.full_name returns the repositorie name
        fetch(`https://raw.githubusercontent.com/${item.full_name}/master/built-with.json`)
          .then(data => {
            item["filters"] = data
            return item
          })
      })
    })
  .then(data => console.log(data))

但是它不起作用!我在控制台中得到了这个:

enter image description here

有人可以帮助我吗?先感谢了。

注意:如果你发现一些语法错误,那是因为我的英语还在学习过程中。


1
这里有几件事情。你不需要将 .then() 链接到 fetch() 上。fetch() 返回一个 Promise。Array.prototype.map() 返回一个数组。把它们放在一起,你最终得到了一个 Promise 数组。你可以使用 Promise.all(arrayOfPs) 来解决这个 Promise 数组。 - Randy Casburn
你需要链式调用 Promise.all。请参考这里 - Brenden
在内部的 fetch('https://raw.githubusercontent… 之前,你漏掉了一个 return - hackape
3个回答

11
一些注意事项。您不需要将.then()链接到fetch()上。fetch()会返回一个promise(承诺)。Array.prototype.map()返回一个数组。合起来,你就得到了一个承诺的数组。您可以使用Promise.all(arrayOfPs)解决承诺数组。
编辑:根据您的评论和问题回顾后,我已重写此内容,以从筛选后的存储库列表中检索技能。

const url = `https://api.github.com/users/RodrigoWebDev/repos?per_page=100&sort=created`;

(async() => {
  // Final results 
  let results;
  try {
    // Get all repositories
    const repos = await fetch(url).then((res) => res.json());
    const responses = await Promise.all(
      // Request file named 'build-with.json' from each repository
      repos.map((item) => {
        return fetch(
          `https://raw.githubusercontent.com/${item.full_name}/master/built-with.json`
        );
      })
    );
    // Filter out all non-200 http response codes (essentially 404 errors)
    const filteredResponses = responses.filter((res) => res.status === 200);
    results = Promise.all(
      // Get the project name from the URL and skills from the file
      filteredResponses.map(async(fr) => {
        const project = fr.url.match(/(RodrigoWebDev)\/(\S+)(?=\/master)/)[2];
        const skills = await fr.json();
        return {
          project: project,
          skills: skills
        };
      })
    );
  } catch (err) {
    console.log("Error: ", err);
  }
  results.then((s) => console.log(s));
})();


你的示例返回了一个 Promise 数组,我需要一个带有键“filters”的新的 Github 项目数组,我该如何得到这个结果? - Rodrigo
这个例子返回了一个HTTP响应的数组。它们都是404错误。我觉得我不理解你的意思或者你在结果中看到了什么。 - Randy Casburn
我重新阅读了你的问题。你没有说明哪些仓库有你所谓的“过滤器”中的这个神奇文件。提供一个包含该文件的仓库,我将检索并打印其内容。 - Randy Casburn
https://github.com/RodrigoWebDev/my-website 和 https://github.com/RodrigoWebDev/border-radius-previewer - Rodrigo
@Rodrigo - 给你! - Randy Casburn
array.map() 中,我像示例一样使用了 fetch()。然而,我在 map 外部使用了 await Promise.all(),并且在内部使用了 await (await fetch(..).json()) - Timo

2
问题在于fetch没有被返回,因此.map()返回undefined。我建议使用async-await解决这个问题。

const url = "https://api.github.com/users/RodrigoWebDev/repos?per_page=100&sort=created";

getData(url).then(data => console.log(data));
  
async function getData(url){
  const response = await fetch(url);
  const data = await response.json();
  const arrOfPromises = data.map(item => fetch(`https://raw.githubusercontent.com/${item.full_name}/master/built-with.json`)
  );
  return Promise.all(arrOfPromises);
}


你甚至都没有改变我的变量名 :-) LOL - Randy Casburn
1
很抱歉,我确实使用了你的示例作为参考。我还点赞了你的答案,因为它是正确的。如果这对你有问题,我会删除此答案。 @RandyCasburn - Arpan Kc
1
不要删除你的答案!它和我的一样有效。我只是逗你玩而已。 - Randy Casburn
你的示例返回了一个 Promise 数组,我需要一个带有键“filters”的新的 Github 项目数组,我该如何得到这个结果? - Rodrigo

1
您有多个问题:
  1. 在map函数内部,您没有返回任何结果
  2. 由于fetch的存在,您的map函数的结果实际上将是另一个Promise。
所以您需要做的是:
  1. 从map中返回promise - 这样您将得到一组promise数组
  2. 使用Promise.all等待来自第1点的所有promise
类似这样:


    var url1 = "https://api.github.com/users/RodrigoWebDev/repos?per_page=100&sort=created";
    var datum = fetch(url1)
      .then((response) => response.json())
      .then((data) => {
          return Promise.all(data.map(item => {
            //item.full_name returns the repositorie name
            return fetch(`https://raw.githubusercontent.com/${item.full_name}/master/built-with.json`)
              .then(data => {
                item["filters"] = data
                return item
              })
          }));
        }).then(data => console.log(data))


嗨,Nikitia。它起作用了,但返回的新对象数组不是过滤器数组,而是fetch的返回值,请参见https://ibb.co/t4Y04gQ。我尝试像这样将响应传递给json https://ibb.co/VV0XT00,但它没有起作用。 - Rodrigo
为了理解那里发生了什么,我需要看看你收到了什么,你可以尝试使用.text()而不是.json() - 也许它会给你一些线索。 - Nikita Chayka
我需要准确地看到你从网络接收到的内容,可能是因为 JSON 在那里被转换成字符串了,或者类似的情况。你可以尝试对 text() 使用 JSON.parse,看看是否有效。 - Nikita Chayka
那个字符串似乎不是一个数组,所以你的API没有返回数组,因此你应该构建自己的逻辑将其转换为数组,可以使用split或其他方法。 - Nikita Chayka
这很奇怪!看看这个例子 https://raw.githubusercontent.com/RodrigoWebDev/my-website/master/built-with.json,这就是我之前提到的包含数组的文件,我正在获取这个文件的内容,难道我构建这个文件的方式有问题吗? - Rodrigo
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接