【问题标题】:Javascript: Making sure one async function doesn't run until the other one is complete; working with promisesJavascript:确保一个异步函数在另一个完成之前不会运行;与承诺一起工作
【发布时间】:2020-03-19 10:19:14
【问题描述】:

我正在从 github 存储库中获取信息。我想获取该仓库中的拉取请求列表,获取与每个拉取请求关联的提交列表,然后对于每个提交,我想获取诸如提交的作者、与每个提交关联的文件数和对每个文件进行的添加和删除次数。我正在使用 axios 和 github API 来完成此任务。我知道如何使用 API,但 Promise 和异步函数使我无法完成任务。我有以下代码:

const axios = require('axios');
var mapOfInformationObjects = new Map();
var listOfCommits = [];
var listOfSHAs = [];
var gitApiPrefix = link I'll use to start fetching data;
var listOfPullRequestDataObjects = [];
var listOfPullRequestNumbers = [];
var mapOfPullNumberToCommits = new Map();

function getAllPullRequests(gitPullRequestApiLink) {
    return new Promise((resolve, reject) => {
        axios.get(gitPullRequestApiLink).then((response) =>{
            listOfPullRequestDataObjects = response['data'];
        var k;
        for (k = 0; k < listOfPullRequestDataObjects.length; k++){
            listOfPullRequestNumbers.push(listOfPullRequestDataObjects[k]['number']);
        }
        resolve(listOfPullRequestNumbers);
    }).catch((error) => {
        reject(error);
    })
})
}

function getCommitsForEachPullRequestNumber(listOfPRNumbers) {
var j;
for (j = 0; j < listOfPRNumbers.length; j++) {
    currPromise = new Promise((resolve, reject) => {
        currentGitApiLink = gitApiPrefix + listOfPRNumbers[j] + "/commits";
        axios.get(currentGitApiLink).then((response) => {
            mapOfPullNumberToCommits.set(listOfPRNumbers[j], response['data']);
            resolve("Done with Pull Request Number: " + listOfPRNumbers[j]);
        }).catch((error) => {
            reject(error);
        })
    })
}

}

function getListOfCommits(gitCommitApiLink){
return new Promise((resolve, reject) => {
    axios.get(gitCommitApiLink).then((response) => {
        resolve(response);
    }).catch((error) => {
        reject(error);
    })
})
}

到目前为止,我做了一些我想按顺序调用的函数。 首先我想调用 getAllPullRequestNumbers(someLink) 然后我想打电话给 getCommitsForEachPullRequestNumber(listofprnumbers) 然后getListOfCommits(anotherLink)

所以它看起来像

getAllPullRequestNumbers(someLink)
getCommitsForEachPullRequestNumber(listofprnumbers)
getListOfCommits(anotherlink)

但是出现了两个问题: 1)我不确定这是否是您调用函数的方式,以便序列中的第一个函数在另一个函数之前完成。 2) 因为我不熟悉 Javascript,所以我不确定,尤其是 getCommitsForEachPullRequestNumber 函数,因为您运行一个循环并在循环的每次迭代中调用 axios.get(),如果这是您在其中处理承诺的方式功能。

这就是您完成这两项任务的方式吗?任何帮助深表感谢。谢谢!

【问题讨论】:

标签: javascript asynchronous promise axios


【解决方案1】:

当您可以一起运行多个异步操作(由 Promise 表示)并且您想知道它们何时全部完成时,您可以使用Promise.all()。您收集一组承诺并将其传递给Promise.all(),它会告诉您它们何时全部完成或其中一个何时触发错误。如果全部完成,Promise.all() 将返回一个 Promise,该 Promise 解析为一组结果(每个异步操作一个)。

当您迭代一个数组来执行您的一组异步操作时,最好使用.map(),因为这可以帮助您创建一个可以提供给Promise.all() 的并行promise 数组。以下是您在 getCommitsForEachPullRequestNumber() 中的操作方法:

function getCommitsForEachPullRequestNumber(listOfPRNumbers) {
    let mapOfPullNumberToCommits = new Map();
    return Promise.all(listOfPRNumbers.map(item => {
        let currentGitApiLink = gitApiPrefix + item + "/commits";
        return axios.get(currentGitApiLink).then(response => {
            // put data into the map
            mapOfPullNumberToCommits.set(item, response.data);
        });
    })).then(() => {
        // make resolved value be the map we created, now that everything is done
        return mapOfPullNumberToCommits;
    });
}

// usage:
getCommitsForEachPullRequestNumber(list).then(results => {
    console.log(results);
}).catch(err => {
    console.log(err);
});

然后,在getListOfCommits() 中,由于 axios 已经返回了一个 Promise,所以没有理由将它包装在手动创建的 Promise 中。也就是说,实际上,考虑一个 Promise 反模式。相反,只需返回 axios 已经返回的承诺。事实上,可能甚至没有理由将它作为一个函数,因为可以直接使用axios.get() 来实现相同的结果:

function getListOfCommits(gitCommitApiLink){
    return axios.get(gitCommitApiLink);
}

然后,在getAllPullRequests() 中,您似乎只是在进行一次axios.get() 调用,然后处理结果。可以这样做:

function getAllPullRequests(gitPullRequestApiLink) {
    return axios.get(gitPullRequestApiLink).then(response => {
        let listOfPullRequestDataObjects = response.data;
        return listOfPullRequestDataObjects.map(item => {
            return item.number;
        });
    });
}

现在,如果您尝试按此顺序依次执行这三个操作:

getAllPullRequests(someLink)
getCommitsForEachPullRequestNumber(listofprnumbers)
getListOfCommits(anotherlink)

您可以将这三个操作中的 Promise 链接在一起以对它们进行排序:

 getAllPullRequests(someLink)
   .then(getCommitsForEachPullRequestNumber)
   .then(mapOfPullNumberToCommits => {
       // not entirely sure what you want to do here, perhaps
       // call getListOfCommits on each item in the map?
   }).catch(err => {
      console.log(err);
 });

或者,如果您将此代码放在async 函数中,那么您可以使用async/awit

 async function getAllCommits(someLink) {
      let pullRequests = await getAllPullRequests(someLink);
      let mapOfPullNumberToCommits = await getCommitsForEachPullRequestNumber(pullRequests);
      // then use getlistOfCommits() somehow to process mapOfPullNumberToCommits
      return finalResults;
 }

 getAllCommits.then(finalResults => {
     console.log(finalResults);
 }).catch(err => {
     console.log(err);
 });

【讨论】:

  • @MohammadO - 这对你有帮助吗?它回答了你的问题吗?如果是这样,您可以通过单击答案左侧的复选标记向社区表明这一点。如果没有,请回复评论,解释您仍然对什么感到困惑。当我们在这里提供帮助时,尤其是当有人发布相当全面的答案时,您至少应该以某种方式做出回应。
  • 忘恩负义的某某刚刚删除了the question I answered,没有一句感谢的话,更不用说谢谢了。一点头绪都没有应该得到制裁,我要把他列入我的黑名单。
  • 我尝试过这样做,但我仍然不明白 Promise 是如何工作的。我尝试用不同的方式声明一堆异步函数,然后创建另一个调用所有异步函数的函数。与上面的人所说的相反,我非常感谢您的帮助,因为它确实更清楚地说明了承诺,但正如我所说,我是 Javascript 的新手,我仍然很难掌握承诺。我删除了另一个问题,因为这是我犯的一个非常愚蠢的错误(递增 var x 而不是 y)。
  • @MohammadO - 不知道我还能说什么。你没有问任何新的东西。我们无法真正提供关于 Promise 的完整教程,因此您需要找到一些好的参考资料并进行一些阅读/学习以帮助更好地理解它们。对于您定义的函数,此答案显示了如何使用 Promise 对多个异步操作进行排序的一般结构,这正是您的问题标题所要求的。我不确定您还想了解关于该主题的哪些内容。
  • @MohammadO - 你在这里通过他人的善意得到帮助。而且,你的行为要么会鼓励人们更多地帮助你,要么会阻止人们再帮助你。删除另一个问题,甚至根本不向试图帮助你的漫游者发表评论都是粗鲁的——不管你的错误多么愚蠢。这将发出一条信息,让您远离您的问题,您可能只是在浪费时间尝试提供帮助。将来,请向那些试图帮助您的人提供反馈(在数小时内)。否则,我们只会假设您没有回应和不考虑周到。
【解决方案2】:

不如 jfriend00 解决方案干净, 但我玩过你的代码,它终于奏效了

https://repl.it/@gui3/githubApiPromises

你会在变量listOfCommits中获得提交列表

我不明白你最后一个函数的目的,所以我放弃了它

【讨论】:

  • 请在这里回答,不要只在github上。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-01
  • 2021-05-25
相关资源
最近更新 更多