如何对两个 http 请求使用 promise

How to use promise with two http requests

我正在尝试发出几个 HTTP 请求,一个在另一个中,但我在重构 JSON 对象时遇到了问题。

我有一个工厂功能,首先我试图获取所有团队,每个团队都有一个 ID,然后我获取每个团队的所有新闻与 ID 相关,并将其放入第一个 JSON 对象中的新闻。

但这不起作用!

.factory('teamsFactory', function ($http,CacheFactory,LocaleManager,$q) 
{

   teams.Getteams= function() 
    {
        var zis=this;
    var promise=$http({method:"GET",url:"http://www.myserver/teams"});
    promise.then(function(response){

    for (var i=0;i<response.data.length;i++) {

     zis.getTeamsNews(response.data[i].idTeam).then(function(newsresponse){

     response.data[i].news=newsresponse.data;

     });
    }


    },alert('error'));
    return promise;         
    }


    teams.getTeamsNews= function(idTeam) 
    {
    var promise=$http({method:"GET",url:"http://www.myserver.com/news?team="+idTeam});
    promise.then(null,alert('error'));
    return promise;         
    }

});

您需要创建自己的承诺,并在完成后解决它,这样:

return $q(function(resolve, reject) {

    $http({method:"GET",url:"http://www.myserver/teams"}).then(function(response){
        var promises = [];
        for (var i=0;i<response.data.length;i++) {
            promises.push(zis.getFavoriteTeamsNews(response.data[i].idTeam)).then(function(newsresponse){
                response.data[i].news=newsresponse.data;
            });
        }
        $q.all(promises).then(function(){
            resolve(response);
        });
    });

    for (var i=0;i<response.data.length;i++) {

     zis.getFavoriteTeamsNews(response.data[i].idTeam).then(function(newsresponse){

     response.data[i].news=newsresponse.data;

     })
});

我认为最好将所有 $http promise 放入一个数组,然后使用 $q.all() 将它们组合在一起,而不是在循环中单独调用它们。试试这个:

请注意,我必须移动您的一些功能并创建虚拟数据等,因此您必须稍微更改它以适合您的应用程序。

DEMO

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope, teamsFactory) {
  $scope.name = 'World';

  teamsFactory.Getteams()
  .then(function(data){
    $scope.teamsData = data;
  });

});

app.factory('teamsFactory', function ($http, $q){

  var teams = {};

  teams.getFavoriteTeamsNews = function(teamId){
    return $http
      .get('news.json')
      .then(function(response){
        console.log('gtTeamNews response', response);
        return response.data[teamId];
      })
  }

  teams.Getteams = function(){

    var zis = this,

        httpConfig = {
          method  : "GET", 
          url     : "teams.json"
        };

    return $http(httpConfig)
      .then(function(response){

        var teamId, promise,

            requests = [];

        for(var i = 0; i <response.data.length; i++){

          teamId  = response.data[i].idTeam;
          promise = teams.getFavoriteTeamsNews(teamId);

          requests.push(promise);

        }

        return $q
          .all(requests)
          .then(function(responses){

            angular.forEach(responses, function(newsresponse, index){
              response.data[index].news = newsresponse;
            });

            return response.data;

          });


      })
      .catch(function(error){
        console.log('error', error);
      });   

  }


  return teams;


  // teams.TeamsNews= function(idTeam){
  //   return $http({method:"GET",url:"http://www.myserver.com/news?team="+idTeam})
  //           .catch(function(){
  //             alert('error')
  //           });

  // }

});

更新

您还可以重构上述内容以利用 promise 链,这在我看来使其更加清晰。这应该给出相同的输出,但更多 'flat',即更少 indentation/callback hell:

DEMO2

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope, teamsFactory) {
  $scope.name = 'World';

  teamsFactory.Getteams()
  .then(function(data){
    $scope.teamsData = data;
  });

});

app.factory('teamsFactory', function ($http, $q){

  var responseData,

      teams = {};

  teams.getFavoriteTeamsNews = function(teamId){
    return $http
      .get('news.json')
      .then(function(response){
        console.log('gtTeamNews response', response);
        return response.data[teamId];
      })
  }

  teams.Getteams = function(){

    var zis = this,

        httpConfig = {
          method  : "GET", 
          url     : "teams.json"
        };

    return $http(httpConfig)
      .then(function(response){

        var teamId, promise,

            requests = [];

        responseData = response.data;

        for(var i = 0; i < responseData.length; i++){

          teamId  = responseData[i].idTeam;
          promise = teams.getFavoriteTeamsNews(teamId);

          requests.push(promise);

        }

        return $q.all(requests);

      })
      .then(function(responses){

        angular.forEach(responses, function(newsresponse, index){
              responseData[index].news = newsresponse;
        });

        return responseData;
      })
      .catch(function(error){
        console.log('error', error);
      });   

  }


  return teams;

});

最终类似的东西..这是原始解决方案..可以通过缓存来增强...

var module = angular.module('myapp', []);

module.factory('teamsFactory', function ($http,CacheFactory,LocaleManager,$q)
{

    function ExtractTeamFromData(data){
        // TODO
        console.log("TODO: Exctract teams from data ...");
    }
    function FindTeamById(teams, tgeamId){
        // TODO
        console.log("TODO: Find team by id ...");
    }
    function ExtractNewsFromData(data){
        // TODO
        console.log("TODO: Exctract news from data ...");
    }


    var GetTeams= function()
    {
        var zis=this;
        var promise = $http({method:"GET",url:"http://www.myserver/teams"});
        var successCallback = function(data, status, headers, config) {
            var teams = ExtractTeamFromData(data);
            return teams;
        };

        var errorCallback = function(reason, status, headers, config) {
            console.error("Some error occured: " + reason);
            return {
                'errorMessage': reason
            };
        }
        promise.then(successCallback,errorCallback);
        return promise;
    }



    var GetTeam = function(idTeam)
    {
        var promise = GetTeams();
        var successTeamsCallback = function(teams, status, headers, config) {
            return FindTeamById(teams, tgeamId);
        };
        var errorTeamsCallback = function(reason, status, headers, config) {
            console.error("Some error occured: " + reason);
            return {
                'errorMessage': reason
            };
        }
        promise.then(successTeamsCallback,errorTeamsCallback);
        return promise;
    }


    var GetTeamsNews = function(idTeam){
        var promise = GetTeam(idTeam);
        var successTeamCallback = function(team, status, headers, config) {
            var newsPromise = $http({method:"GET",url:"http://www.myserver.com/news?team="+idTeam});
            var successNewsCallback = function(data, status, headers, config) {
                var news = ExtractNewsFromData(data);
                return news;
            };
            var errorNewsCallback = function(reason, status, headers, config) {
                console.error("Some error occured: " + reason);
                return {
                    'errorMessage': reason
                };
            }
            newsPromise.then(successNewsCallback,errorNewsCallback);
            return newsPromise;
        };
        var errorTeamCallback = function(reason, status, headers, config) {
            console.error("Some error occured: " + reason);
            return {
                'errorMessage': reason
            };
        }
        promise.then(successTeamCallback,errorTeamCallback);
        return promise;
    }

    return {
        GetTeams: GetTeams,
        GetTeam: GetTeam,
        GetTeamsNews: GetTeamsNews
    };

});