UPDATE: Adrian Quark has a much safer approach for the cache in his comment. I guess I should have tested mine better with other functions than the computational ones I was doing
A short Javascript function I made in a project to cache result from functions in Javascript. You can use this function where it makes sense to cache.
The cache method
cacheMethod.cache = {};
function cacheMethod(context, fn) {
var funcName = fn.toString();
funcName = funcName.substr('function '.length);
funcName = funcName.substr(0, funcName.indexOf('('));
context[funcName] = function() {
if (cacheMethod.cache[funcName] == null)
cacheMethod.cache[funcName] = {};
// Create a unique key of parameters
var key = Array.slice.call(arguments).join('|');
if (cacheMethod.cache[funcName][key] == null)
cacheMethod.cache[funcName][key] = fn.apply(this, arguments);
return cacheMethod.cache[funcName][key];
};
}
Usage
If we have a function like isPrime borrowed from John Resig:
function isPrime( num ) {
var prime = num != 1; // Everything but 1 can be prime
for ( var i = 2; i < num; i++ ) {
if ( num % i == 0 ) {
prime = false;
break;
}
}
return prime;
}
we can make the isPrime function cache-able with a single line of:
cacheMethod(this, isPrime);
No when we try to call the isPrime 100 times with a large prime number, this first round is calculated and all subsequent rounds use the cache. You can see the difference by removing the cacheMethod line.
for (var i=0; i<100; i++)
document.write(isPrime(58750291)+'<br/>');
Full example here: cache.html.
While looking at the Facebook Connect API I was curious to see that it uses custom XML tags for it’s elements, for example <fb:login-button/>. After the page is loaded the tag is replaced with <a href="..." ><img src='...' /></a> if the user is not logged in and a profile image and name if the user is already logged in.
So I could better understand how this works I created a little sample were I extracted the important parts from the API. The sample takes in a instance of an User object and displays a profile picture and name of the user with the gs:profile-image and gs:profile-text tags.
First there is the main parser. It starts by defining the objects of the sample API in an array of knownElements. Then the parseDomTree function loops through all of the known elements and find all objects in the document that correspond to that tag.
gsml.js
var GS = {};
GS.GSML = {
ProfileText : function(el) {
var span = document.createElement('span');
span.innerHTML = GS.user.username;
el.innerHTML = "";
el.appendChild(span);
},
ProfileImage : function(el) {
// Some logic to create the image from the logged in user
var img = document.createElement('img');
img.setAttribute('src', GS.user.img);
img.setAttribute('onclick', el.getAttribute('clickhandler'));
el.innerHTML = "";
el.appendChild(img);
}
};
GS = {
knownElements : [
{key:'profile-image', class:GS.GSML.ProfileImage},
{key:'profile-text', class:GS.GSML.ProfileText}],
user : null,
init : function(user) {
this.user = user;
},
parseDomTree : function(context) {
// Loop through all known elements in our namespace
for (var i=0; i<this.knownElements.length; i++) {
// Find all tags for current known element
var elements = context.getElementsByTagName("GS:"+ this.knownElements[i]['key']);
for (var j=0; j<elements.length; j++) {
// Call the associated function to parse this tag
this.knownElements[i]['class'](elements[j]);
}
}
}
};
In the HTML that uses the sample API there are four elements of interest; include of the sample javascript api, define the User object, tell the API to parse the DOM and add the custom API tags to the HTML body.
thefile.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:gs="http://www.gunnarsteinn.com/2009/gsml">
<head>
<script type="text/javascript" src="gsml.js"></script>
<script type="text/javascript">
var user = {
username : 'Click Image',
img : 'http://www.gunnarsteinn.com/wp-content/uploads/tf.jpg'
};
function imgClicked() {
user.username = 'Tobias Funke';
GS.parseDomTree(document);
}
</script>
</head>
<body onload="GS.init(user); GS.parseDomTree(document)">
<gs:profile-image clickhandler="imgClicked();"></gs:profile-image>
<gs:profile-text></gs:profile-text>
</body>
</html>
And the results:
Function.prototype.bind = function(){
var fn = this, args = Array.prototype.slice.call(arguments), object = args.shift();
return function(){
return fn.apply(object,
args.concat(Array.prototype.slice.call(arguments)));
};
};
If you want to spent an hour studying how this one function in JavaScript works there is an excellent demonstration at John Resig’s blog.
The code uses three types of method invocation in just a couple of lines (shift(), apply and call). Isn’t JavaScript too complex?
Ég finn alltaf fyrir mikill bloggþörf þó ég hafi margoft byrjað og nákvæmlega jafn oft hætt (ef við teljum þessa færslu ekki með, ennþá).
Klassíska vandamálið, þegar það er nóg að blogga um hef ég ekki tíma til að blogga um það, og þess á milli, þegar ég hef nægan tíma, hef ég ekkert að blogga um…
Recent Comments