Inside my own Angular service, how do you get the

2019-09-01 18:32发布

问题:

I'm having trouble figuring out the success and error callbacks inside $http in angular and the "then" part of a promise. The $http service returns a promise. Is the "success" callback an example of a "then"? What if I stick $http inside my own service? How would I do this?

I think code is easier to show my questions:

app.controller('MainCtrl', function ($scope, $log, BooksService) {
    BooksService.retrieveAllBooks().then(function(results) {
      $scope.allBooks = results;
    });
  });


app.factory('BooksService', function($http,$log) {
  var service = {
    retrieveAllBooks: function() {
      return $http({
        method: 'GET','https://hugebookstore.org/allbooks'
        headers: {
            "Content-Type": "application/json",
            "Accept": "application/json"
        }
      }).success(function(data, status, headers, config) {
         var allbooks = transformDataIntoBooksArray(data);//this function exists and just takes raw data and turns them into Book objects
         return allbooks;/*how is this "success" callback related to the "then"() callback in app.controller above?*/
      };
      }).error(function(data, status, headers, config) {
        $log.error('here is an error'+data + status + headers + config);
      });
    }
  };
  return service;
});

Questions about the app.controller code:

do I need to use a "then()" function inside app.controller?

I just want my controller to fetch me a list of all the books using the BooksService. The BooksService already has a "then" type of clause, which is the "success" callback. It seems like I have an unnecssary "then". Is that true?

Also, when is the "then" called, and can I put anything in the then's callback function's parameters?

I don't understand what parameters are supplied by default and what I can add.

Questions about the app.factory code:

First, this is what I understand the code to be doing.

I'm creating a BooksService using the factory() methods and not the service() methods available in Angular. I'm defining a function called retrieveAllBooks() that under the hood, is making an asynchronous GET request using $http in Angular, which itself is a service. RetrieveAllBooks() is a nothing more than a wrapper around the $http GET service, which makes it easy for clients to simply call BooksService.retrieveAllBooks() and be handed an array of Book objects.

When is the "success" callback executed and what is its relation to the "then" callback in my app.controller?

It doesn't appear that a return value inside my success() callback is ever returned back to app.controller. Why?

How can I get the allbooks array returned back to the app.controller which is what originally called BooksService.retrieveAllBooks()?

Are there any other parameters allowed in the success callback?

What do I need to return from the retrieveAllBooks() function definition? Do I return the $http promise alone, or do I need to return something from both the success and error callbacks as well?

I know this is longwinded but I hope that someone can help me, b/c this to pattern--separating out my network calls into its own service layer as opposed to calling $http directly inside my controller layer, will be done over and over again.

Thanks!!

回答1:

The success and error handlers are specific to the promise returned by $http. However, they're similar to .then(function onFulfill(){}, function onReject(){}).

It's up to you if you want to return that promise directly or implement something else.

Generally, your controller shouldn't be concerned about how your service handled the request. Thus, in my opinion, you shouldn't return that promise directly. Just handle the success and error case in your service. Return the result if the request succeeds and throw an Error if the request fails.

You can then use the generic .then(function onFulfill(){}, function onReject(){}) pattern in your controller, as this is always valid and expected with promises in Angular.

The onFulfill callback always receives your result as a parameter, the onReject callback receives the Error as a parameter.

So, what options do you have? Either drop your .success and .error callbacks in your service altogether and handle the transformation in the success case in your controller, or create a new deferred promise to return the transformed results:

app.factory('BooksService', function($http,$log,$q) {
  var service = {
    retrieveAllBooks: function() {
      var deferred = $q.defer();
      $http({
        method: 'GET','https://hugebookstore.org/allbooks'
        headers: {
            "Content-Type": "application/json",
            "Accept": "application/json"
        }
      }).success(function(data, status, headers, config) {
         var allbooks = transformDataIntoBooksArray(data);//this function exists and just takes raw data and turns them into Book objects
         deferred.resolve( allbooks );
      };
      }).error(function(data, status, headers, config) {
        $log.error('here is an error'+data + status + headers + config);
        deferred.reject( new Error( 'here is an error'+data + status + headers + config );
      });
      return deferred.promise;
    }
  };
  return service;
});

Although, we can save that if we consider: - Errors are tracked by Angular already - The deferred is excess, and can be avoided - Content-Type and Accept are generated by Angular and the serer anyway. - We can save the anonymous wrapper for our action

So, we end up with:

app.factory('BooksService', function($http) {
  return {
    retrieveAllBooks: function() { 
      return $http.get('https://hugebookstore.org/allbooks').
             then(transformDataIntoBooksArray); // Error tracked by Angular already
      }
    }
});