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()
};
source to share
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);
})
source to share