$ q.defer()不使用Angular服务

时间:2022-12-23 20:33:55

I'm new to angular's $q and I'm trying to build a service that makes an API call and returns it back to the controller.

我是angular的$ q的新手,我正在尝试构建一个API调用服务并将其返回给控制器。

Problem: No matter how I seem to format it, the service returns right before it gets to $http.get(...)

问题:无论我如何格式化它,服务都会在它到达$ http.get(...)之前返回

Service:

服务:

   // methods: query new, get existing
  makeRequest: function(url, following) {
      // create promise
      var deferred = $q.defer();

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

              console.log(res);
              deferred.resolve(res.data);
          });

      return deferred.promise;
  },

  getFeed: function(user) {
      console.log('>> userService[getUser]: retrieving user...');


      if (!this.activities) {
          // Request has not been made, setting user profile. 
          console.log('>> userService[getUser]: No user stored, making request...');
          var following = this.compileArray(user);
          console.log(following);
          this.activities = this.makeRequest('api/network/activities', following);
      };

      // Return the myObject stored on the service
      return this.activities;
  }

Controller

调节器

$scope.recentActivity = activityService.getFeed(profile);

// also tried
activityService.getFeed(profile).then(function (res) {
                  $scope.recentActivity = res;
                  console.log(res);
                }); 

EDIT : 9:40am 05/06/2015

编辑:上午9:40 05/06/2015

If possible, I'd like to retrieve the activity list in the controller from the service in the same way I would if it were new (using .then). Is that possible/ bad practice?

如果可能的话,我想从服务中检索控制器中的活动列表,就像它是新的一样(使用.then)。这是可能/不好的做法吗?

  getFeed: function(user) {
    if (!this.activities) { 
      ...
    } else {
      feedPromise = $q(function(resolve){ resolve(this.activities) });
      console.log(feedPromise);
      // returns: {$$state: Object, then: function, catch: function, finally: function}

      feedPromise.then(function(res) {
        console.log(res);
        // returns: undefined
      });

      console.log(that.activities);
      // Works, returns list of activities. 

   }

3 个解决方案

#1


5  

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){...})).

除非您将带有回调的基于非承诺的API转换为基于承诺的API,否则无需使用$ q.defer(即使这样,建议使用$ q(函数(解析,拒绝){。 ..}))。

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

$ http已经返回一个承诺 - 只返回那个(或链接的.then承诺);

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.

其次,承诺返回API会立即同步返回承诺 - 而不是结果。你需要一个.then才能得到结果。

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.

最后,一旦API是异步的,它应始终是异步的 - 不要将其转换为同步或有时同步API。因此,无论在哪里,一直到数据的最终接收者,您都需要使用.then处理程序。

So, your service API can be made quite simple:

因此,您的服务API可以非常简单:

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:

控制器中的用法与任何其他基于promise的API一样:

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

#2


0  

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.

在了解@New Dev的评论中指出的延迟反模式后,我编辑了这个答案。有关详细说明,请参阅@New Dev的答案。谢谢@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;                 
        });

#3


-1  

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

我认为如果你想拥有响应对象,你需要使用.success而不是.then。

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

          console.log(res);
          deferred.resolve(res.data);
      });

#1


5  

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){...})).

除非您将带有回调的基于非承诺的API转换为基于承诺的API,否则无需使用$ q.defer(即使这样,建议使用$ q(函数(解析,拒绝){。 ..}))。

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

$ http已经返回一个承诺 - 只返回那个(或链接的.then承诺);

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.

其次,承诺返回API会立即同步返回承诺 - 而不是结果。你需要一个.then才能得到结果。

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.

最后,一旦API是异步的,它应始终是异步的 - 不要将其转换为同步或有时同步API。因此,无论在哪里,一直到数据的最终接收者,您都需要使用.then处理程序。

So, your service API can be made quite simple:

因此,您的服务API可以非常简单:

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:

控制器中的用法与任何其他基于promise的API一样:

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

#2


0  

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.

在了解@New Dev的评论中指出的延迟反模式后,我编辑了这个答案。有关详细说明,请参阅@New Dev的答案。谢谢@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;                 
        });

#3


-1  

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

我认为如果你想拥有响应对象,你需要使用.success而不是.then。

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

          console.log(res);
          deferred.resolve(res.data);
      });