DOM Caching Revisited
I recently found www.domcached.com. It was not exactly what I’ve looked for, so I changed some bits here, some bits there. This is the current version I’m currently working with. I consider adding real HTML5 database support. So what it’s for? DomCache is a trivial wrapper for the use of DOM Storage provided by modern browsers. It’s modelled after “memcached” and uses Prototype for JSON handling instead of working with Strings only.
DomCache = ( function() {
var storage = {};
var backend = false;
var incrdecr = function( key, delta, namespace, initial, decr ) {
var namespace = namespace || 'default';
var delta = delta || 1;
var initial = initial || 0;
var time = time || false;
if ( !key || ( ( typeof key != 'string' ) && ( typeof key != 'number' ) ) ) {
throw new TypeError();
}
if ( ( typeof namespace != 'string' ) && ( typeof namespace != 'number' ) ) {
throw new TypeError();
}
if ( typeof delta != 'number' ) {
throw new TypeError();
}
if ( time && ( time < ( new Date() ).getTime() ) ) {
time = ( new Date() ).getTime() + time;
}
if ( !storage[namespace] ) {
storage[namespace] = {};
}
if ( !storage[namespace].hasOwnProperty( key ) || ( typeof storage[namespace][key] != 'number' ) ) {
storage[namespace][key].value = initial;
save();
return initial;
}
if ( decr ) {
storage[namespace][key].value -= delta;
} else {
storage[namespace][key].value += delta;
}
save();
return value || true;
};
var save = function() {
if ( backend ) {
try {
backend.dom_storage = Object.toJSON( storage );
return true;
} catch ( ex ) {
if ( $( 'elm_domcached' ) ) {
try {
$( 'elm_domcached' ).setAttribute( 'domcached', backend.dom_storage );
$( 'elm_domcached' ).save( 'domcached' );
return true;
} catch (ex ) {
}
}
}
}
return false;
};
// initialization
( function() {
if ( 'localStorage' in window ) {
backend = window.localStorage;
} else if ( 'globalStorage' in window ) {
backend = window.globalStorage[document.domain];
} else if ( 'addBehavior' in ( new Element( 'div' ) ) ) {
$( document.getElementsByTagName( 'body' )[0] ).insert( '
' );
$( 'elm_domcached' ).load( 'domcached' );
try {
var data = $( 'elm_domcached' ).getAttribute( 'domcached' );
} catch ( ex ) {
var data = "{}";
}
backend = {
dom_storage: {}
};
if ( data && data.length ) {
backend.dom_storage = data;
}
} else {
return;
}
if ( ( 'dom_storage' in backend ) && backend.dom_storage ) {
try {
storage = String( backend.dom_storage ).evalJSON();
} catch ( ex ) {
backend.dom_storage = "{}";
}
} else {
backend.dom_storage = "{}";
}
} )();
// the public interface
return {
set: function( key, value, time, namespace ) {
var namespace = namespace || 'default';
var time = time || false;
if ( !key || ( ( typeof key != 'string' ) && ( typeof key != 'number' ) ) ) {
throw new TypeError();
}
if ( ( typeof namespace != 'string' ) && ( typeof namespace != 'number' ) ) {
throw new TypeError();
}
if ( time && ( time < ( new Date() ).getTime() ) ) {
time = ( new Date() ).getTime() + Math.ceil( time );
}
if ( !storage[namespace] ) {
storage[namespace] = {};
}
storage[namespace][key] = {
value: value,
time: time
};
save();
return value || true;
},
get: function( key, namespace ) {
var namespace = namespace || 'default';
if ( ( typeof namespace != 'string' ) && ( typeof namespace != 'number' ) ) {
throw new TypeError();
}
if ( storage[namespace] && storage[namespace][key] && ( !storage[namespace][key].time || ( storage[namespace][key].time < ( new Date() ).getTime() ) ) ) {
return storage[namespace][key].value;
}
return null;
},
add: function( key, value, time, namespace ) {
var namespace = namespace || 'default';
var time = time || false;
if ( !key || ( ( typeof key != 'string' ) && ( typeof key != 'number' ) ) ) {
throw new TypeError();
}
if ( ( typeof namespace != 'string' ) && ( typeof namespace != 'number' ) ) {
throw new TypeError();
}
if ( time && ( time < ( new Date() ).getTime() ) ) {
time = ( new Date() ).getTime() + Math.ceil( time );
}
if ( !storage[namespace] ) {
storage[namespace] = {};
}
storage[namespace][key] = {
value: value,
time: time
};
save();
return value || true;
},
replace: function( key, value, time, namespace ) {
var namespace = namespace || 'default';
var time = time || false;
if ( !key || ( ( typeof key != 'string' ) && ( typeof key != 'number' ) ) ) {
throw new TypeError();
}
if ( ( typeof namespace != 'string' ) && ( typeof namespace != 'number' ) ) {
throw new TypeError();
}
if ( time && ( time < ( new Date() ).getTime() ) ) {
time = ( new Date() ).getTime() + time;
}
if ( !storage[namespace] ) {
storage[namespace] = {};
}
storage[namespace][key] = {
value: value,
time: time
};
save();
return value || true;
},
incr: function( key, delta, namespace, initial ) {
return incrdecr( key, delta, namespace, initial );
},
decr: function( key, delta, namespace, initial ) {
return incrdecr( key, delta, namespace, initial, true );
},
remove: function( key, namespace ) {
var namespace = namespace || 'default';
if ( ( typeof namespace != 'string' ) && ( typeof namespace != 'number' ) ) {
throw new TypeError();
}
if ( storage[namespace] && storage[namespace][key] ) {
delete storage[namespace][key];
for ( var i in delete storage[namespace] ) {
if ( storage[namespace].hasOwnProperty( i ) ) {
return save();
}
}
delete storage[namespace];
return save();
}
},
removeAll: function() {
storage = {};
return save();
}
}
} )();
Here's a little example:
About this entry
You’re currently reading “DOM Caching Revisited,” an entry on Markus Nix
- Published:
- 2.3.10 / 11am
- Category:
- Javascript
- Tags:
- dom caching
Comments are closed
Comments are currently closed on this entry.