如何在Promises循环后运行回调?

时间:2017-11-10 20:22:47

标签: javascript node.js promise

具体来说,给定一个数据列表,我想循环遍历该列表,并在之后将其全部组合之前对该数据的每个元素进行一次获取。事实上,正如所写的那样,代码会立即遍历整个列表,立即启动所有操作。然后,即使获取操作仍然在运行,然后在完成所有运行之后调用,然后才能处理数据。

我读了一些关于将所有Promises放入数组,然后将该数组传递给Promise.all()调用,接着是一个然后可以按预期访问所有处理过的数据的内容,但是我我不确定在这种情况下如何做到这一点,因为我在这个for循环中嵌套了Promises

        for(var i in repoData) {
            var repoName = repoData[i].name;
            var repoUrl = repoData[i].url;
            (function(name, url) {
                Promise.all([fetch(`https://api.github.com/repos/${username}/${repoData[i].name}/commits`),
                    fetch(`https://api.github.com/repos/${username}/${repoData[i].name}/pulls`)])
                .then(function(results) {   
                    Promise.all([results[0].json(), results[1].json()])
                    .then(function(json) {
                        //console.log(json[0]);
                        var commits = json[0];
                        var pulls = json[1];
                        var repo = {};
                        repo.name = name;
                        repo.url = url;
                        repo.commitCount =  commits.length;
                        repo.pullRequestCount = pulls.length;
                        console.log(repo);
                        user.repositories.push(repo);
                    }); 
                });
            })(repoName, repoUrl);
        }
    }).then(function() {
        var payload = new Object();
        payload.user = user;
        //console.log(payload);
        //console.log(repoData[0]);
        res.send(payload);
    });

1 个答案:

答案 0 :(得分:4)

通常,当您需要为数组中的所有项运行异步操作时,答案是使用Promise.all(arr.map(...)),这种情况似乎也不例外。

另请注意,您需要return回调中的then值才能将值传递到下一个then(或Promise.all聚合所有内容)。

当遇到复杂情况时,将其分解成更小的部分会有所帮助。在这种情况下,您可以隔离代码以查询单个仓库的数据到其自己的功能中。完成后,查询所有数据的代码归结为:

Promise.all(repoData.map(function (repoItem) {
  return getDataForRepo(username, repoItem);
}))

请尝试以下方法:

// function to query details for a single repo
function getDataForRepo(username, repoInfo) {
  return Promise
    .all([
      fetch(`https://api.github.com/repos/${username}/${repoInfo.name}/commits`),
      fetch(`https://api.github.com/repos/${username}/${repoInfo.name}/pulls`)
    ])
    .then(function (results) {
      return Promise.all([results[0].json(), results[1].json()])
    })
    .then(function (json) {
      var commits = json[0];
      var pulls = json[1];

      var repo = {
        name: repoInfo.name,
        url: repoInfo.url,
        commitCount: commits.length,
        pullRequestCount: pulls.length
      };

      console.log(repo);
      return repo;
    });
}

Promise.all(repoData.map(function (repoItem) {
  return getDataForRepo(username, repoItem);
})).then(function (retrievedRepoData) {
  console.log(retrievedRepoData);

  var payload = new Object();
  payload.user = user;
  //console.log(payload);
  //console.log(repoData[0]);
  res.send(payload);
});