Async/Transaction/Something problem
See original GitHub issueI’m trying to cache data in a simple cacheService module I built for my angular app.
The data gets returned from the WebApi. I “put” the data into a store and return a promise so my calling client can continue the process.
From here I want to access the store where I just saved data and apply various filters.
I think the data is not ready for me to query because I can’t seem to get to it.
I can’t seem to find much documentation on “put” to understand how to know when it’s done saving so that I know when it’s safe to fetch the data again. All the examples fetch the data immediately as if it were a synchronous call. Maybe it is. I’m new so I don’t quite understand yet.
All I know is I spent all day on this and now all night.
What happens is when I press a button to retrieve data I get nothing back into the UI, when I have not previously requested the data. The second time I press my button I get data but it’s the data from the original request and not the newest data.
Summary:
- Fetch data via Web Api and place it into an IndexedDB data store with YDN-DB
- Return control to my UI
- UI executes a query against the IndexedDB data store.
- No data is to be found.
Thoughts?
Here is my cacheService. It’s probably a mess to a veteran but again, I’m new.
mashupApp.service(‘cacheService’, function ($http, $q, $log) {
var isCacheStale = function (cacheName, minutes) {
// dbCache: is 'mashCache'
// store: No store is provided but might be added later to remove constaint 'mashCacheAge'
// subject: is the name of the cache being evaluated.
// minutes: is the number of minutes before the cache is considered stale.
var deferred = $q.defer();
var result = true;
// get milliseconds version of minutes.
var ageToleranceMilliseconds = (minutes * 60) * 1000;
var currentDateMilliseconds = new Date().getTime();
// checking dbCacheReady because, if a page loads to quickly, before the cache database is ready
// then accessing it will cause an error.
(function wait() {
if (dbCacheReady) {
// The database is ready so go ahead and begin checking for stale data.
try {
dbCache.executeSql('SELECT * FROM mashCacheAge WHERE id = \'' + cacheName + '\'').then(function (record) {
$log.log('mashCacheAge record for: [ ' + cacheName + ' ] cache.');
$log.log(record);
// if no record is returned then it is considered stale.
var recordCount = record.length;
if (recordCount > 0) {
var durationMilliseconds = currentDateMilliseconds - record[0].updatedDate;
// Check if the data is stale.
if (durationMilliseconds > ageToleranceMilliseconds) {
result = true;
}
else { result = false; }
deferred.resolve(result);
}
else {
// no records found so this cache is considered stale.
deferred.resolve(true);
}
});
}
catch (e) {
// no data store for the cache was found so it is considered stale.
deferred.resolve(true);
}
} else {
// Giving the cache database a moment to set up.
setTimeout(wait, 500);
}
})();
return deferred.promise;
};
// Updates the age of any cacheName.
var updateCacheAge = function (cacheName) {
// updates the mashCacheAge. This helps track how old/stale a cache is.
var cacheJSON = {
id: cacheName,
updatedDate: new Date().getTime()
};
dbCache.put({ name: 'mashCacheAge', keyPath: 'id' }, cacheJSON);
}
var getCache = function (cacheName) {
var deferred = $q.defer();
// waiting for dbCacheReady because accessing the cache to early causes an error.
(function wait() {
if (dbCacheReady) {
dbCache.executeSql('SELECT * FROM \'' + cacheName + '\'').then(function (record) {
deferred.resolve(record);
});
} else { setTimeout(wait, 500); }
})();
return deferred.promise;
}
// --------------------------------------------------------------------------------
// If the machCache is too old then all the data is wiped out and the user starts again.
// --------------------------------------------------------------------------------
var minutesInOneWeek = 10080; // 10080 = 1 week
isCacheStale('mashCacheStart', minutesInOneWeek).then(function (result) {
//alert(result);
if (result) {
// TODO: Add this to mashup logging.
// the mashCache is too old and needs cleared.
//ydn.db.deleteDatabase('mashCache');
//setTimeout(function () { alert('mashCache was stale so deleted.'); }, 1);
//dbCache.clear();
// The first time through there will be no objects and this clear will fail.
// TODO: update this to could objects before calling
try { dbCache.clear(); } catch (e) { }
$log.log('mashCache was stale so deleted.');
updateCacheAge('mashCacheStart');
};
});
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
return {
// Retrieve cache
getCache: function (cacheName) {
var deferred = $q.defer();
getCache(cacheName).then(function (data) {
deferred.resolve(data);
});
return deferred.promise;
},
getData: function (cacheName, schema, webApiUrl, staleMinutes) {
var deferred = $q.defer();
// var cacheName = 'getItems2';
// Check if the cache is stale.
isCacheStale(cacheName, staleMinutes).then(function (cacheIsStale) {
// If cache stale then get new data.
if (cacheIsStale) {
// cache has become stale so retrieving fresh data.
$http.get(webApiUrl, { withCredentials: true })
.success(function (data) {
//#region
// -------------------------------------------------------------------------------
// Schema will be passed in so that it can be generated on the fly.
// When a schema for an object store changes it will break and cause
// an error. We will look for that error and simply delete the
// indexedDB database so the next time this is caused the new schema
// can take hold. This doesn't seem ideal but the impact is only
// to performance when schemas change for cached data.
// -------------------------------------------------------------------------------
// Normally the schema is defined up front and versioned. For the cache we want
// developers to have one less thing to consider and allow the mashup core
// to be less coupled to the caching needs of other mashup applications.
// -------------------------------------------------------------------------------
//#endregion
try {
// add data to cache
dbCache.put(schema, data);
// updateCacheAge
updateCacheAge(cacheName);
}
catch (err) {
$log.log(err);
indexedDB.deleteDatabase('mashCache');
$log.log("IndexedDB error on updating a cache. Deleted database to allow new schema.");
alert("IndexedDB error on updating a cache. Deleted database to allow new schema.");
}
// return web api data to the client
// async alert() so the performance perception isn't affected.
//setTimeout(function () { alert('web api data'); }, 1);
deferred.resolve(data);
})
.error(function () {
// if the call fails then return the current cache.
// TODO: make an async call to let someone know a service failed?
alert("Web Api Error");
getCache(cacheName).then(function (data) {
// async alert()
// setTimeout(function () { alert('cache data'); }, 1);
deferred.resolve(data);
});
});
} else {
// cached data is still good so return it.
getCache(cacheName).then(function (data) {
// async alert()
//setTimeout(function () { alert('cache data'); }, 1);
deferred.resolve(data);
});
}
});
return deferred.promise;
}
};
});
Here is the client code. Or at least it’s a client to the service. (portion)
},
getExample4items: function (staleMinutes, id) {
var deferred = $q.defer();
var cacheName = 'MashupExamples_example4items';
var schema = { name: cacheName, keyPath: 'id' };
var webApiUrl = 'http://localhost:50000/api/MashupExamples/Items/';
try {
cacheService.getData(cacheName, schema, webApiUrl, staleMinutes).then(function (data) {
try {
var record = _.where(data, { 'id': parseInt(id) });
deferred.resolve(record);
} catch (e) { $log.log(e); }
});
} catch (e) { $log.log(e); }
return deferred.promise;
},
You’ll notice that I’m passing in the schema with the call. That’s because I don’t want to define a schema for the entire application up front and deal with all the versioning. I seem to have been able to work around this.
Thanks, Bob
Issue Analytics
- State:
- Created 9 years ago
- Comments:9 (4 by maintainers)
The bug has been fixed in rel 1.0.3. http://jsfiddle.net/kyawtuns/Ya3Cv/1/
That was very fast. I’ll get the new code and test it. I was on vacation last week or I would have done this sooner.
I didn’t know you were the author of YDN-DB. Great job and I love the library. Thank you.