$q.defer() not working with Angular service

↘锁芯ラ 提交于 2019-12-05 14:01:18

There is no need to use a $q.defer unless you are converting a non-promise based API with callbacks into a promise-based API (and even then, it is recommended to use $q(function(resolve, reject){...})).

$http already returns a promise - just return that (or a chained .then promise);

var httpResponsePromise = $http.get(url); // returns a promise
var actualDataPromise = httpResponsePromise.then(function(resp){ return resp.data; });

return actualDataPromise;

or shorter (and typical):

return $http.get(url).then(function(response){ 
   return response.data;
});

Second, a promise-returning API returns the promise - not the result - right away, synchronously. You need a .then to get the result.

Lastly, once an API is async, it should always be async - don't convert it to a sync or a sometimes-sync API. So, everywhere, all the way to the end recipient of the data, you need to use a .then handler.

So, your service API can be made quite simple:

makeRequest: function(url, following){
   return $http.get(url, {params: { "following": following }})
             .then(function(response){
                return response.data;
             });
},

getFeed: function(user) {
   var that = this;

   var feedPromise;

   if (!that.activities) {
      var following = this.compileArray(user);

      feedPromise = this.makeRequest('api/network/activities', following)
          .then(function(activities){
             that.activities = activities;
             return activities;
          });
   } else {
      feedPromise = $q(function(resolve){ resolve(that.activities); });
      // or you could have cached the old feedPromise and returned that
   }

   return feedPromise;
}

The usage in the controller is just like with any other promise-based API:

activityService.getFeed(profile)
   .then(function(activities) {
      $scope.recentActivity = activities;
   }); 

After learning about the deferred anti-pattern as pointed out in the comments by @New Dev, I have edited this answer. Please see @New Dev's answer for a detailed explanation. Thanks @New Dev.

Service

    makeRequest: function(url, following) {
        return $http.get(url, {
                params: {
                    "following": JSON.stringify(following)
                }
            }).then(function(res) {
                return res.data;
            });
    },    
    getFeed: function(user) {

        var that = this;

        if (!that.activities) {
            var following = that.compileArray(user);

            return that.makeRequest('api/network/activities', following)        
                .then(function(activities){
                    that.activities = activities;
                    return that.activities;
                });
        } else {
            return $q(function(resolve) {
                resolve(that.activities);
            });
        }    
    }

Controller

    activityService
        .getFeed(profile)
        .then(function (activities) {
            $scope.recentActivity = activities;                 
        });

i think you need to use .success instead of .then if you want to have the response object.

$http.get(url, {
         params: {
          "following": JSON.stringify(following)
      }
  })
      .success(function(res) {

          console.log(res);
          deferred.resolve(res.data);
      });
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!