【问题标题】:Return paginated output recursively with Fetch API使用 Fetch API 递归返回分页输出
【发布时间】:2020-10-01 21:01:42
【问题描述】:

总结

我想使用 JavaScript 的 Fetch API 递归地将分页输出整理到一个数组中。从 Promise 开始,我认为 async/await 函数会更合适。

尝试

这是我的方法:

global.fetch = require("node-fetch");

async function fetchRequest(url) {
  try {
    // Fetch request and parse as JSON
    const response = await fetch(url);
    let data = await response.json();

    // Extract the url of the response's "next" relational Link header
    let next_page = /<([^>]+)>; rel="next"/g.exec(response.headers.get("link"))[1];

    // If another page exists, merge it into the array
    // Else return the complete array of paginated output
    if (next_page) {
      data = data.concat(fetchRequest(next_page));
    } else {
      console.log(data);
      return data;
    }

  } catch (err) {
    return console.error(err);
  }
}

// Live demo endpoint to experiment with
fetchRequest("https://jsonplaceholder.cypress.io/posts?_page=9");

对于这个演示,它应该产生 2 个请求,产生一个包含 20 个对象的数组。虽然返回了数据,但我无法理解如何将它整理成一个数组。任何指导将不胜感激。感谢您的宝贵时间。

解决方案 #1

感谢@ankit-gupta:

async function fetchRequest(url) {
  try {
    // Fetch request and parse as JSON
    const response = await fetch(url);
    let data = await response.json();

    // Extract the url of the response's "next" relational Link header
    let next_page;
    if (/<([^>]+)>; rel="next"/g.test(response.headers.get("link"))) {
      next_page = /<([^>]+)>; rel="next"/g.exec(response.headers.get("link"))[1];
    }

    // If another page exists, merge its output into the array recursively
    if (next_page) {
      data = data.concat(await fetchRequest(next_page));
    }
    return data;
  } catch (err) {
    return console.error(err);
  }
}

fetchRequest("https://jsonplaceholder.cypress.io/posts?_page=9").then(data =>
  console.log(data)
);

对于每一页,后续调用都是递归进行的,并将它们连接到一个数组中。是否可以使用类似于this answerPromises.all 并行链接这些调用?

附带说明一下,为什么 StackOverflow Snippets 在第二次 Fetch 中失败?

【问题讨论】:

    标签: javascript node.js recursion pagination fetch-api


    【解决方案1】:

    你需要将next_page包装在一个条件中,否则会导致最后一次调用时出现类型错误(因为/&lt;([^&gt;]+)&gt;; rel="next"/g.exec(response.headers.get("link"))将为空)

    在连接数据之前,您需要得到解决的承诺。

    对你的代码做一些小的改动可以得到正确的输出:

    global.fetch = require("node-fetch");
    
    async function fetchRequest(url) {
      try {
        // Fetch request and parse as JSON
        const response = await fetch(url);
        let data = await response.json();
    
        // Extract the url of the response's "next" relational Link header
        let next_page;
        if(/<([^>]+)>; rel="next"/g.exec(response.headers.get("link")))
            next_page = /<([^>]+)>; rel="next"/g.exec(response.headers.get("link"))[1];
    
        // If another page exists, merge it into the array
        // Else return the complete array of paginated output
        if (next_page) {
          let temp_data = await fetchRequest(next_page); 
          data = data.concat(temp_data);
        }
    
        return data;
      } catch (err) {
        return console.error(err);
      }
    }
    
    // Live, demo endpoint to experiment
    fetchRequest("https://jsonplaceholder.cypress.io/posts?_page=9").then(data => {
        console.log(data);
    });
    

    【讨论】:

    • 感谢您如此详细的回复,非常感谢!与其在条件和逻辑中重复RegExp.exec,不如在条件中使用RegExp.test 会更有效吗?是否建议通过将fetchRequest() 调用直接移动到data.concat() 来绕过temp_data?你觉得这个脚本的结构怎么样?可以改进吗?是否可以并行链接调用similar to this
    • 对于并行链接调用,您需要删除从响应头中获取下一个链接的依赖。您是否需要依赖每个响应的next 关系链接?我的意思是,如果你知道起点是https://jsonplaceholder.cypress.io/posts?_page=8,终点是https://jsonplaceholder.cypress.io/posts?_page=10,你可以自己创建中间链接,对吧?
    • 是的,您绝对可以将fetchRequest() 电话直接转移到data.concat()。我这样写只是为了让人们清楚地了解正在发生的事情。
    猜你喜欢
    • 2018-08-14
    • 1970-01-01
    • 2018-02-14
    • 1970-01-01
    • 1970-01-01
    • 2019-08-04
    • 1970-01-01
    • 2019-03-17
    • 2015-07-16
    相关资源
    最近更新 更多