【问题标题】:Handling async code to combine multiple returned responses处理异步代码以组合多个返回的响应
【发布时间】:2017-05-09 13:21:30
【问题描述】:

我正在编写一些查询 github API 的异步代码。我正在执行的每个 API 调用都通过此代码运行,并且我点击了“weeksOfYear”控制台日志。我要做的是将所有这些 api 调用捆绑到一个大数组中,这样我就可以一起处理所有数据。我相信这将涉及回调,但我不知道把它放在哪里。我在下面包含了我的代码。

我相信它会以这种方式返回,因为它都在一个承诺中。当我尝试向代码添加另一个承诺时,我收到一条错误消息,上面写着“then is undefined”。这是因为我需要返回一个 promise 对象。所以,我认为解决方案是使用回调。

谢谢!

$.ajax({
  method: 'GET',
  url: 'https://api.github.com/orgs/lodash/repos' ,
  contentType: 'application/json',
  beforeSend: function(xhr){
      return xhr.setRequestHeader("Authorization", "token adbfde986475bbee66b2e22b4375be4d34adc098")
    }
})
.then(function (data){
  // console.log('GOT THIS DATA', data);
  return data.map(function(val){
      return val.name;
    });
})
.then(function (newData){
  newData.forEach(function(repoName){
    pagination(repoName, function(storage) {
      storage = storage.filter(function(PR){
        if(PR.merged_at !== null){
          return true;
           }
        })
        var weeksOfYear = {};
        console.log('STORAGE HERE IS', storage);
        storage.filter(function(mergedPR){
          if (moment(mergedPR.merged_at).year() === 2016){
            return true;
          }
        }).forEach(function(mergedPR){
          var weekMerged = moment(mergedPR.merged_at).week();
            if(!weeksOfYear[weekMerged]){
              weeksOfYear[weekMerged] = 1;
              // weeksOfYear[yearMerged] = yearMerged
            }else{
              weeksOfYear[weekMerged] += 1;
              // weeksOfYear[moment(mergedPR.merged_at).year()] = moment(mergedPR.merged_at).year()
            }
          })
          console.log('weeks of Year are', weeksOfYear)
        })
      })
    })

这是分页的样子:

var pagination = function (repoName, callback) {
      var num = 1;
      var storage = [];
      function recursiveHelper(repoName, num){
         $.ajax({
        method: 'GET',
        url: 'https://api.github.com/repos/lodash/' + repoName + '/pulls?state=closed&page=' + num,
        contentType: 'application/json',
        beforeSend: function(xhr){
          return xhr.setRequestHeader("Authorization", "token adbfde986475bbee66b2e22b4375be4d34adc098")
        }
      })
      .then(function(numPullRequests){
        // console.log('numPullRequests', numPullRequests);
        storage = storage.concat(numPullRequests);
        if(numPullRequests.length !== 30){
          return callback(storage);
        }

        recursiveHelper(repoName, num + 1);
      })
        // console.log('this value is', numPullRequests);
      }

      recursiveHelper(repoName, num)

}

【问题讨论】:

  • pagination(repoName, function(storage) { 是异步函数吗?当你说bundle all of these api calls - 你指的是哪个“api调用”,因为唯一看起来像api调用的函数是pagination
  • 是的,很遗憾,它太大了,无法粘贴到 cmets 中。它不断调用 github API 来收集不同的拉取请求(一次最多可以检索 30 个,然后将它们连接到一个数组中。我已经添加了我的其余代码,我希望能澄清事情。
  • 这听起来像是 Promise.all 的工作。你可以建立一个promise数组并将它们传递给Promise.all。传递给Promise.allthen 块的函数将接收各个promise 的结果数组。

标签: javascript jquery callback promise


【解决方案1】:

好的,因为分页是异步的,并且不返回承诺(即使它使用承诺!但它的递归性质使其成为现实)对现有代码的最小更改会产生这个

...
.then(function(newData) {
    // use Array#map and Promise.all ...
    return Promise.all(newData.map(function(repoName) {
        // create a Promise
        return new Promise(function(resolve, reject) {
            pagination(repoName, function(storage) {
                storage = storage.filter(function(PR) {
                    if (PR.merged_at !== null) {
                        return true;
                    }
                })
                var weeksOfYear = {};
                console.log('STORAGE HERE IS', storage);
                storage.filter(function(mergedPR) {
                    if (moment(mergedPR.merged_at).year() === 2016) {
                        return true;
                    }
                }).forEach(function(mergedPR) {
                    var weekMerged = moment(mergedPR.merged_at).week();
                    if (!weeksOfYear[weekMerged]) {
                        weeksOfYear[weekMerged] = 1;
                        // weeksOfYear[yearMerged] = yearMerged
                    } else {
                        weeksOfYear[weekMerged] += 1;
                        // weeksOfYear[moment(mergedPR.merged_at).year()] = moment(mergedPR.merged_at).year()
                    }
                });
                console.log('weeks of Year are', weeksOfYear);
                // resolve the promise in the callback
                resolve(weeksOfYear);
            });
        });
    }));
}).then(function(result) {
    // results is an array of weeksOfYear
});

但是,如果您更改 pagination 以返回一个承诺,像这样

var pagination = function(repoName) {
    var num = 1;
    var storage = [];
    function recursiveHelper(repoName, num) {
        return $.ajax({
            method: 'GET',
            url: 'https://api.github.com/repos/lodash/' + repoName + '/pulls?state=closed&page=' + num,
            contentType: 'application/json',
            beforeSend: function(xhr) {
                return xhr.setRequestHeader("Authorization", "token adbfde986475bbee66b2e22b4375be4d34adc098")
            }
        })
        .then(function(numPullRequests) {
            // console.log('numPullRequests', numPullRequests);
            storage = storage.concat(numPullRequests);
            if (numPullRequests.length !== 30) {
                return storage;
            }
            return recursiveHelper(repoName, num + 1);
        });
        // console.log('this value is', numPullRequests);
    }
    return recursiveHelper(repoName, num);
};

你的代码可以改成这个

...
.then(function(newData) {
    // again, use Array#map and Promise.all
    return Promise.all(newData.map(function(repoName) {
        // no need for new Promise as pagination returns a promise
        return pagination(repoName)
        .then(function(storage) {
            storage = storage.filter(function(PR) {
                if (PR.merged_at !== null) {
                    return true;
                }
            })
            var weeksOfYear = {};
            console.log('STORAGE HERE IS', storage);
            storage.filter(function(mergedPR) {
                if (moment(mergedPR.merged_at).year() === 2016) {
                    return true;
                }
            }).forEach(function(mergedPR) {
                var weekMerged = moment(mergedPR.merged_at).week();
                if (!weeksOfYear[weekMerged]) {
                    weeksOfYear[weekMerged] = 1;
                    // weeksOfYear[yearMerged] = yearMerged
                } else {
                    weeksOfYear[weekMerged] += 1;
                    // weeksOfYear[moment(mergedPR.merged_at).year()] = moment(mergedPR.merged_at).year()
                }
            });
            console.log('weeks of Year are', weeksOfYear);
            // just return weeksOfYear
            return weeksOfYear;
        });
    }));
}).then(function(result) {
    // results is an array of weeksOfYear
});

注意:如果你没有可用的 Promise

替换

return Promise.all(newData.map(function(repoName) {

return $.when.apply($, newData.map(function(repoName) {

}).then(function(result) {
    // results is an array of weeksOfYear
});

}).then(function() {
    // arguments will be weeksOfYear
});

对于第一个答案,您还需要更改

 return new Promise(function(resolve, reject) {
    pagination(repoName, function(storage) {
        //... snip
        console.log('weeks of Year are', weeksOfYear);
        // resolve the promise in the callback
        resolve(weeksOfYear);
    });
 });

var d = $.Deffered();
pagination(repoName, function(storage) {
     //... snip
     console.log('weeks of Year are', weeksOfYear);
     // resolve the promise in the callback
     d.resolve(weeksOfYear);
});
return d.promise();

【讨论】:

  • 对不起,如果您测试了第二个代码并且它失败了,我在错误的地方返回了
  • Promise.all() 如果可用,肯定会起作用,但没有证据表明它是。我们只知道jQuery ..... 因此jQuery.when()
  • 注:添加了使用$.when的更改
  • 非常感谢!这是一个很好的答案:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-13
  • 1970-01-01
  • 2019-05-28
  • 2015-09-03
  • 2018-10-21
相关资源
最近更新 更多