在服务中处理$ http响应

bsr*_*bsr 233 javascript angularjs angular-http

我最近公布的我面对这个问题的详细说明,这里的SO.由于我无法发送实际$http请求,因此我使用超时来模拟异步行为.在@Gloopy的帮助下,从我的模型到视图的数据绑定工作正确

现在,当我使用$http而不是$timeout(在本地测试)时,我可以看到异步请求成功并data在我的服务中填充了json响应.但是,我的观点不是更新.

在这里更新了Plunkr

Pet*_* BD 418

这是一个可以满足您需求的Plunk:http://plnkr.co/edit/TTlbSv?p = preview

这个想法是你直接使用promises和他们的"then"函数来操作和访问异步返回的响应.

app.factory('myService', function($http) {
  var myService = {
    async: function() {
      // $http returns a promise, which has a then function, which also returns a promise
      var promise = $http.get('test.json').then(function (response) {
        // The then function here is an opportunity to modify the response
        console.log(response);
        // The return value gets picked up by the then in the controller.
        return response.data;
      });
      // Return the promise to the controller
      return promise;
    }
  };
  return myService;
});

app.controller('MainCtrl', function( myService,$scope) {
  // Call the async method and then do stuff with what is returned inside our own then function
  myService.async().then(function(d) {
    $scope.data = d;
  });
});
Run Code Online (Sandbox Code Playgroud)

这是一个稍微复杂的版本,可以缓存请求,因此您只能第一次创建它(http://plnkr.co/edit/2yH1F4IMZlMS8QsV9rHv?p=preview):

app.factory('myService', function($http) {
  var promise;
  var myService = {
    async: function() {
      if ( !promise ) {
        // $http returns a promise, which has a then function, which also returns a promise
        promise = $http.get('test.json').then(function (response) {
          // The then function here is an opportunity to modify the response
          console.log(response);
          // The return value gets picked up by the then in the controller.
          return response.data;
        });
      }
      // Return the promise to the controller
      return promise;
    }
  };
  return myService;
});

app.controller('MainCtrl', function( myService,$scope) {
  $scope.clearData = function() {
    $scope.data = {};
  };
  $scope.getData = function() {
    // Call the async method and then do stuff with what is returned inside our own then function
    myService.async().then(function(d) {
      $scope.data = d;
    });
  };
});
Run Code Online (Sandbox Code Playgroud)

  • 在用"then"拦截服务后,有没有办法在控制器中调用成功和错误方法? (13认同)
  • @ GFoley83 - 在这里:http://plnkr.co/edit/2yH1F4IMZlMS8QsV9rHv?p = preview.如果您查看控制台,您将看到请求只进行一次. (5认同)
  • @PeteBD我想你也可以直接在控制器中使用`$ scope.data = myService.async()`. (3认同)
  • @PeteBD如果我想从各种控制器多次调用我的`myService.async()`,你将如何组织服务,这样只有第一个请求的`$ http.get()`和所有后续请求只返回在第一次调用`myService.async()`时设置的本地对象数组.换句话说,我想避免对JSON服务发出多个不必要的请求,而实际上我只需要创建一个. (2认同)
  • @ Blowsie-我更新了Plunks.原来这里是(更新到1.2RC3):http://plnkr.co/edit/3Nwxxk?p=preview下面是一个使用服务:http://plnkr.co/edit/a993Mn?p=preview (2认同)

all*_*kim 82

让它变得简单.这很简单

  1. 退回promise服务(无需使用then)
  2. then在控制器中使用

演示.http://plnkr.co/edit/cbdG5p?p=preview

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

app.factory('myService', function($http) {
  return {
    async: function() {
      return $http.get('test.json');  //1. this returns promise
    }
  };
});

app.controller('MainCtrl', function( myService,$scope) {
  myService.async().then(function(d) { //2. so you can use .then()
    $scope.data = d;
  });
});
Run Code Online (Sandbox Code Playgroud)


Tos*_*osh 58

因为它是异步的,所以$scope在ajax调用完成之前获取数据.

您可以$q在您的服务中使用创建promise并将其返回给控制器,并且控制器在then()调用中获取结果promise.

在您的服务中,

app.factory('myService', function($http, $q) {
  var deffered = $q.defer();
  var data = [];  
  var myService = {};

  myService.async = function() {
    $http.get('test.json')
    .success(function (d) {
      data = d;
      console.log(d);
      deffered.resolve();
    });
    return deffered.promise;
  };
  myService.data = function() { return data; };

  return myService;
});
Run Code Online (Sandbox Code Playgroud)

然后,在你的控制器中:

app.controller('MainCtrl', function( myService,$scope) {
  myService.async().then(function() {
    $scope.data = myService.data();
  });
});
Run Code Online (Sandbox Code Playgroud)

  • +1我最喜欢这个,因为它比其他人更多OO.但是有没有理由你不这样做`this.async = function(){`和`this.getData = function(){return data}`?我希望你明白我的意思 (2认同)

Gui*_*e86 23

tosh shimayama有一个解决方案,但如果你使用$ http返回promises并且promises可以返回一个值的事实你可以简化很多:

app.factory('myService', function($http, $q) {
  myService.async = function() {
    return $http.get('test.json')
    .then(function (response) {
      var data = reponse.data;
      console.log(data);
      return data;
    });
  };

  return myService;
});

app.controller('MainCtrl', function( myService,$scope) {
  $scope.asyncData = myService.async();
  $scope.$watch('asyncData', function(asyncData) {
    if(angular.isDefined(asyncData)) {
      // Do something with the returned data, angular handle promises fine, you don't have to reassign the value to the scope if you just want to use it with angular directives
    }
  });

});
Run Code Online (Sandbox Code Playgroud)

coffeescript中的一个小演示:http://plunker.no.de/edit/ksnErx?live =preview

您的plunker更新了我的方法:http://plnkr.co/edit/mwSZGK?p = preview


Has*_*lly 7

我认为更好的方法是这样的:

服务:

app.service('FruitsManager',function($q){

    function getAllFruits(){
        var deferred = $q.defer();

        ...

        // somewhere here use: deferred.resolve(awesomeFruits);

        ...

        return deferred.promise;
    }

    return{
        getAllFruits:getAllFruits
    }

});
Run Code Online (Sandbox Code Playgroud)

在控制器中,您可以简单地使用:

$scope.fruits = FruitsManager.getAllFruits();
Run Code Online (Sandbox Code Playgroud)

Angular会自动将解析awesomeFruits成的$scope.fruits.

  • deferred.resolve()?更准确的是,$ http电话在哪里?另外,为什么要在.service中返回一个对象? (4认同)

小智 6

我有同样的问题,但当我在互联网上冲浪时,我明白$ http默认返回一个承诺,然后我可以在返回"数据"后使用"then".看代码:

 app.service('myService', function($http) {
       this.getData = function(){
         var myResponseData = $http.get('test.json').then(function (response) {
            console.log(response);.
            return response.data;
          });
         return myResponseData;

       }
});    
 app.controller('MainCtrl', function( myService, $scope) {
      // Call the getData and set the response "data" in your scope.  
      myService.getData.then(function(myReponseData) {
        $scope.data = myReponseData;
      });
 });
Run Code Online (Sandbox Code Playgroud)