如何对 Github 上的用户的所有存储库发出一个异步请求

How to make one async request for all repositories of a user on Github

以下大概就是我需要做的事情了。但这是写在 Python 中的,我没有掌握一些细节: How to get all repositories of a specific GitHub user.

到目前为止,这是我的代码:

function loadRepositories() {

  let arrOfRepos = []

  for (var i = 1, j = 1; j > 0; i++) {
    var req = new XMLHttpRequest();

    // must be synchronous or else, j is assigned below, before the response is received from send(). While send() is going on, j is assigned the value of the empy responseText. And the loop doesn't continue.

    req.open('GET', 'https://api.github.com/users/-user-/repos?page=' + i, false)
    req.send()
    arrOfRepos = arrOfRepos.concat(JSON.parse(req.responseText))
    var j = JSON.parse(req.responseText).length
  }
  showRepositories(arrOfRepos)
}

我只想以某种方式向 URL 提出一个请求。似乎使用分页的唯一方法是多次联系 URL,然后测试我是否应该再打一个电话。

我试图在 showRepositories() 中测试 reqlinks 键,但是 this.links returns undefined.

我的作品有效,但它非常缓慢且丑陋。有没有一种方法可以调用 API 并更快地构建我的单独响应?

一种方法是使用 Promise and wait for all the promises to resolve with Promise.all。您将必须进行一次初始调用以获取 Link header 并检查最后一页是什么。然后进行 (number_of_page - 1) 异步调用(在回调函数中获取响应)。

var url = "https://api.github.com/users/google/repos?per_page=100";
var repos = [];

function sendRequest(url, parseLink) {
  return new Promise(function(resolve, reject) {
    var xhr = new XMLHttpRequest();
    xhr.open("GET", url, true);
    xhr.send();
    xhr.onreadystatechange = function() {
      if (xhr.readyState === 4) {
        if (xhr.status === 200) {
          var resp = xhr.responseText;
          var respJson = JSON.parse(resp);
          if (parseLink) {
            resolve(getLastPage(xhr.getResponseHeader("Link")), respJson);
          } else {
            resolve(respJson);
          }
        } else {
          reject(xhr.status);
        }
      }
    }
  });
}

function getLastPage(link) {
  if (link) {
    var linkArr = link.split(',');
    for (var i = 0; i < linkArr.length; i++) {
      if (linkArr[i].indexOf('rel="last"') != -1) {
        return new URL(linkArr[i].substring(linkArr[i].lastIndexOf("<") + 1, linkArr[i].lastIndexOf(">"))).searchParams.get('page');
      }
    }
  }
  return 1;
}

sendRequest(url, true).then(function(lastPage, data) {
  console.log("last page is " + lastPage);
  repos = repos.concat(data);
  var requests = [];
  if (lastPage > 1) {
    for (var i = 2; i < parseInt(lastPage) + 1; i++) {
      requests.push(sendRequest(url + "&page=" + i).then(function(data) {
        repos = repos.concat(data);
      }));
    }
    Promise.all(requests).then(function(data) {
        console.log("all promises have been resolved, total repo count : " + repos.length);
      })
      .catch(function(err) {
        console.log('Error executing promisses', err);
      });
  } else {
    console.log("only 1 request was necessary, total repo count : " + repos.length);
  }
});

在上面的代码片段中,每次解决一个承诺时,结果都会连接到 repos 数组,一旦解决了所有承诺,您就可以处理您的数据。

请注意,您可以使用 per_page=100 到 return 每个请求最多 100 个存储库,而不是默认的 30 个。