Receive data synchronously when cached, or access asynchronously when not available

I have an AngularJS app that uses routing and views. When a specific view is loaded and the controller is instantiated, I have to prepare some model data $scope

. This data can be provided by a dependent service, or when the service does not have it, I make an asynchronous call to get it from the server.

When I finally have this data, I have to change it a bit and then put it on $scope

.

This, I think, falls into the lazy / promises API just fine. Receiving data from a service is done using a service instance $resource

and is already a promise. The only problem I am facing is converting my synchronous code to a deferred / promise pattern.

Question

How can I change my handling of synchronous code to become async, so my data-providing function always returns a promise that will be immediately resolved when using the synchronization code and after a while when calling my server asynchronously?

So the process:

  • try to get data synchronously
  • If sync fails, try async
  • success / failure
    • available data => manipulate it
    • data unavailable (anyway) => reset state

What i tried

var getData = function() {
    var defer = $q.defer();

    defer.promise
        .then(function () {
            // return cached item
            return dataCacheService.get("dataKey");
        })
        .then(function(data) {
            // cache returned data?
            if (!data)
            {
                // no? get it from server returning a promise
                return dataResource.get({
                    set: "models",
                    id: $routeParams.id
                });
            }
        })
        .then(function (data) {
            // server returned data?
            if (!!data) // <= PROBLEM!!! This is not null, but is a Resource with unresolved promise?
            {
                // yes? fine. manipulate it
                delete data.details;
                delete data.type.description;

                $scope.lists.set(data.type);

                return data;
            }
            // no data. sorry...
            $scope.resetType();
        })
        // something went wrong
        .catch($scope.resetType);

    // initiate deferred execution
    defer.resolve();

    return defer.promise;
}

...

$scope.model = {
    item: getData()
};

      

+3


source to share


1 answer


You can make your service so that it always returns a promise, if data is available, it will return a promise immediately after the REST call. For example, your service might look like this:

var dataThatMayOrMayNotBeAvailable=null;

var getDataThatMayOrMayNotBeAvailable=function(){
   var deferred = $q.defer();
   if(dataThatMayOrMayNotBeAvailable){
       deferred.resolve(dataThatMayOrMayNotBeAvailable);
    }else{
     $http({...}).success(function(data){
       dataThatMayOrMayNotBeAvailable=data;
       deferred.resolve(data);
      });
    }

return deferred.promise;

}

      



Using:

getDataThatMayOrMayNotBeAvailable().then(function(data){
   console.log(data);
})

      

+3


source







All Articles