在服务中处理 $http 响应

IT技术 javascript angularjs angular-http
2021-02-04 20:03:08

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

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

在这里更新了 Plunkr

6个回答

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

这个想法是你直接使用 Promise 和它们的“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;
  });
});

这是一个稍微复杂的版本,它缓存请求,因此您只需第一次创建(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;
    });
  };
});
有没有办法在服务拦截后仍然调用控制器中的成功和错误方法then
2021-03-11 20:03:08
@PeteBD 我认为您也可以$scope.data = myService.async()直接在控制器中使用。
2021-03-19 20:03:08
@PeteBD 如果我想myService.async()从各种控制器多次调用我的服务,您将如何组织服务以便仅$http.get()针对第一个请求执行该服务,并且所有后续请求仅返回一个本地对象数组,该数组在第一次调用时设置为myService.async(). 换句话说,我想避免向 JSON 服务发出多个不必要的请求,而实际上我只需要发出一个请求。
2021-03-21 20:03:08
@Blowsie- 我已经更新了 Plunks。这是原来的(更新到 1.2RC3):plnkr.co/edit/3Nwxxk?p=preview这是一个使用服务:plnkr.co/edit/a993Mn?p=preview
2021-03-27 20:03:08
@GFoley83 - 给你:plnkr.co/edit/2yH1F4IMZlMS8QsV9rHv?p=preview如果您查看控制台,您会看到该请求仅发出一次。
2021-04-04 20:03:08

让它简单点。就这么简单

  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;
  });
});
在您的链接中,它是app.factory,而在您的代码中它是app.serviceapp.factory在这种情况下应该是这样。
2021-03-20 20:03:08
似乎每次我遇到 Angular 问题时@allenhwkim 都有答案!(本周第三次 - 很棒的 ng-map 组件顺便说一句)
2021-03-25 20:03:08
app.service 也工作。另外 - 这对我来说看起来是最优雅的解决方案。我错过了什么吗?
2021-03-30 20:03:08
我只是想知道如何用 status_code 把成功和错误放在这里
2021-03-31 20:03:08

因为是异步的,所以$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;
});

然后,在您的控制器中:

app.controller('MainCtrl', function( myService,$scope) {
  myService.async().then(function() {
    $scope.data = myService.data();
  });
});
这个例子是一个经典的延迟反模式没有必要制造Promise,$q.defer因为$http服务已经返回了Promise。如果$http返回错误,返回的Promise将挂起此外,.success.error方法已被弃用并已从 AngularJS 1.6 中删除
2021-03-22 20:03:08
@bicycle 我想要它以同样的方式,但它不会工作,因为必须完全解决Promise。如果您不这样做并尝试像往常一样访问它,您将在访问内部数据时收到引用错误。希望有意义?
2021-03-26 20:03:08
+1 我最喜欢这个,因为它比其他的更 OO。但是没有任何理由,你不这样做this.async = function() {,并this.getData = function() {return data}我希望你明白我的意思
2021-04-02 20:03:08
如果我理解正确,deffered = $q.defer()如果我想调用 myService.async() 两次或更多次,则有必要在 myService.async 中添加
2021-04-06 20:03:08

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

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
    }
  });

});

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

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

我会按照你的方法进一步尝试。但是,我喜欢在服务中捕获结果而不是返回。在此处查看与此相关的问题stackoverflow.com/questions/12504747/...我喜欢在控制器中以不同的方式处理 $http 返回的数据。再次感谢你的帮助。
2021-03-12 20:03:08
或者,您可以使用服务中的 $scope.$emit 和 ctrl 上的 $scope.$on 来告诉您控制器数据已返回,但我并没有真正看到好处
2021-03-15 20:03:08
你可以在服务中使用Promise,如果你不喜欢 $watch 你可以做 ´promise.then(function(data){ service.data = data; }, onErrorCallback);`
2021-03-17 20:03:08
我添加了一个从你的分叉出来的 plunker
2021-03-19 20:03:08

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

服务:

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

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

        ...

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

        ...

        return deferred.promise;
    }

    return{
        getAllFruits:getAllFruits
    }

});

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

$scope.fruits = FruitsManager.getAllFruits();

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

deferred.resolve()?请更精确一点,$http 调用在哪里?另外,为什么要在 .service 中返回一个对象?
2021-03-30 20:03:08