Photo Credit: kenteegardin via Compfight cc
This is an object-oriented Servoy tutorial on how to use an object as a cache in Servoy. Using an object to cache data can solve a lot of coding challenges, as well as significantly boost the performance of your code. For example, it can be used to manage foundsets that a collection of methods will work with. Rather than loading a foundset over and over again in each method that is called, you can cache the foundset and retrieve it when you need it. You can also retrieve the entire foundset, not just the first 200 records (which is all that Servoy will load by default), as well as the total record count for the foundset. In addition, some methods you call could modify the foundset and store it back in the cache, ready for the next method that needs to work with the data, avoiding expensive databaseManager.saveData() calls. Other methods may be filtering the foundset, using omitRecord(), and hence by using a cache to retrieve the foundset, your methods are always working with all the right data.
Keep in mind that a cache can be used for more than just foundsets. You can extend it to store any kind of values by key. The cache can be setup when the main method initializes, taking a snapshot of the data at that point in time, so that all methods can access it. Later the cache can be cleared freeing the memory, ready for the next time when the process starts all over. All your objects storing your cached data, and any utility methods you create to work with the data, are all in one place, making your code elegant, highly maintainable, and easily extendable.
Here is an example of a single global cache object, with self managing methods, capable of storing an unlimited number of foundsets based on table name or any user defined key. We will walk through each part in this Servoy tutorial so you can see what is going on here.
// Created in globals.js var oCache = { // object used to store foundsets by key fs : { // an example of how the foundset object will be stored by key t_data: { fs: null, fsCount: null } }, clearAll : function(){ oCache.fs = {}; return; }, fsGet : function(sTableName, optKey, optFoundset){ // Use the cached fs or create it var _fs, _key = sTableName, iCount = 0; if(optKey) _key = optKey; if (!oCache.fs[_key]){ oCache.fs[_key] = {}; } if (!oCache.fs[_key].fs){ if (!optFoundset){ _fs = databaseManager.getFoundSet("test", sTableName); }else{ _fs = optFoundset; } _fs.loadAllRecords(); iCount = _fs.getSize(); if (iCount > 199) iCount = databaseManager.getFoundSetCount(_fs); // if more than 200 oCache.fs[_key].fsCount = iCount; _fs.getRecord(iCount); // load all records oCache.fs[_key].fs = _fs; // store entire fs } _fs = oCache.fs[_key].fs.duplicateFoundSet(); // return a duplicate of the fs return _fs; }, fsClear : function(key){ if (oCache.fs[key]){ oCache.fs[key] = null; } return true; }, fsReset : function(sTableName, optKey){ var _key = sTableName; if (optKey) _key = optKey; oCache.fsClear(_key); return oCache.fsGet(sTableName, optKey, null); }, fsSet : function(sTableName, optKey, optFoundset){ var _key = sTableName; if (optKey) _key = optKey; oCache.fsClear(_key); return oCache.fsGet(sTableName, optKey, optFoundset); }, fsCount : function(sTableName, optKey){ var _key = sTableName; if (optKey) _key = optKey; if(oCache.fs[_key] && oCache.fs[_key].fsCount) return oCache.fs[_key].fsCount; return null; } };
We start out by creating an oCache object in our global.js file and an object in that called fs to store foundsets. We are going to store foundsets and the record count in these objects that we added to the oCache.fs object and identify them using a key. In our example, an object called ‘t_data’ has been added with two properties, fs and fsCount. This is the format we are going to use when we cache new foundsets and record counts by key.
The oCache object also has several utility methods that perform the following functions on the cache:
To use the global cache, you can do the following (assuming Servoy 7.3, otherwise drop the scope prefix):
/*** @type{JSFoundset} ***/var fs = scopes.globals.oCache.fsGet(sTableName, null, null); // optional key and fs
This will create the foundset the first time it is called, and then reuse the cache until fsClear is called.
Getting the foundset record count for the loops is easy as well, using:
var iSize = scopes.globals.oCache.fsCount(sTableName, null); // optional key
Finally, to clear the foundset from the cache and start over next time:
scopes.globals.oCache.fsClear(sKey); // or use fsClearAll()
Using a cache has several advantages:
[bra_list style=’star-list’]Even if you don’t want to use a global cache object like I show here, at least use function memoization. This uses a local object in a function to build a cache and can improve the code performance, avoiding methods from calculating the same thing over and over again.
Bottom-line, use a cache, whenever and wherever you can; cache is definitely king when it comes to increasing code performance. It also helps you solve a number of technical problems, and keeps everything neatly organized in one place.
This is a Servoy tutorial on how to optimize code performance. A while back, I had…
This is an object-oriented Servoy tutorial on how to use function memoization with Servoy. Function memoization…
This is an object-oriented Servoy tutorial on how to use object-oriented programming in Servoy. Javascript’s core…
This is an object-oriented Servoy tutorial on how to use inheritance patterns in Servoy. I use…
This is an object-oriented Servoy tutorial on how to use prototypal inheritance in Servoy. When…
This is an object-oriented Servoy tutorial on how to use multiple inheritance with Servoy. If you…