Everything about Web and Network Monitoring

Memoizing Javascript Snippets in Local Storage

Javascript performance tipsThese simple truths:

  1. registers are faster than memory,
  2. memory is faster than external storage,
  3. external storage is faster than the local network, and
  4. the local network is faster than the Internet

provide performance hints for web applications. One such hint is that we should store components on the local hard disk rather than retrieving them from a server.

Today we’re going to have some fun! We’re going to take that hint and combine it with memorization, a concept that’s been around since the 1990’s or earlier.

Memoization tells us to go get what we need the first time we need it, but to cache it locally so we don’t have to go get it a second time. The following JavaScript function serves that purpose.

This function is written to demonstate a point, not for inclusion in production code. It still needs rigorous error checking and better error handling.

 

    //This code sample shows how to download JavaScript
    //snippets on demand, but only if they weren't
    //previously downloaded.  When the snippet is
    //downloaded the first time, it is placed into local
    //storage.  Whenever it is requested thereafter, it is
    //pulled from local storage instead of being downloaded
    //a second time.
    //This code was released into the public domain by its
    //author, Warren Gaebel, on 2012.07.02.

001 function getCode (snippetName) {
002   snippetVariableName = "jss$" + snippetName;
003   if (localStorage && localStorage[snippetVariableName]) {
004     return localStorage[snippetVariableName];
005   }else{
006     var httpRequest = new XMLHttpRequest();
007     httpRequest.open("GET", snippetName+".js", false);
008     httpRequest.send();
009     if (httpRequest.status == 200 || httpRequest.status == 304) {
010       if (localStorage && !localStorage[snippetVariableName]) {
011         localStorage[snippetVariableName] = httpRequest.responseText;
012       }//end if
013       return httpRequest.responseText;
014     }else{   //httpRequest.status != 200 && httpRequest.status != 304
015       alert("Error executing XMLHttpRequest call!");
016     }//end if (httpRequest.status == 200 || httpRequest.status == 304)
017   }//end if (localStorage && localStorage["fn$"+ snippetName])
018 }//end function activateFunction (snippetName) {
019 </script></head><body>
020 <script type="text/JavaScript">
021 eval(getCode("alertMeSnippet"));
    </script></body></html>

Line 3 determines whether localStorage is available and if the code snippet is in it. If so, it returns the snippet from localStorage in line 4. If it is not available in localStorage, lines 6-16 get it from the server, save it in localStorage, and return it to the caller.

Lines 6-8 get the snippet from the server. Line 9 checks to see if there were any problems. Codes 200 and 304 tell us that everything is fine. [200 says we got it from the server; 304 says we got it from a cache.]

If everything went well up to this point, lines 10-12 add the snippet to localStorage if localStorage exists and the snippet is not already there. Line 13 then returns the snippet to the caller.

If something goes wrong, line 15 uses an alert box to let us know.

Line 21 is an example invocation. It calls getCode to retrieve alertMeSnippet.js from localStorage or the server. The eval function then executes the snippet. Note that it could just as easily have stored the snippet in a string variable for other purposes.

This technique will most likely be used to download function definitions. If each function (or family of functions) is in its own .js file, use getCode to retrieve it. The functions will be available for use after the code is eval’d (but watch out for potential scope issues).

Room for Improvement

Some issues must be addressed before using this technique:

  • Not all browsers support localStorage.
  • What do we do if we don’t get a 200 or 304 return code?
  • There’s a limited amount of space in localStorage. Currently, if we want more, we’re out of luck.
  • When we move to the next version of the snippet, we can simply change its name. However, the old snippet is still in localStorage. We need to remember to delete the old one or we’ll soon run out of space.
  • The above code assumes that the snippet is in the same server directory as the current web page.
  • Each invocation of the above getCode is synchronous. Asynchronous would be better.
  • If the web page’s name or location changes, it gets a brand new, empty localStorage. The old localStorage is still there, cluttering up the user’s hard disk. More importantly, whatever was saved in it is now inaccessible to the web page.

Conclusion

Programmers can store JavaScript code snippets in localStorage on the client machine’s hard disk. The first time the snippet is used, it is downloaded from the server (or a cache), which is a slight performance hit. However, every subsequent time the snippet is used, it is retrieved from the client machine’s disk, which eliminates network access completely.Local disks are faster than the Internet, so this technique offers a serious performance improvement.

About Warren Gaebel

Warren wrote his first computer program in 1970 (yes, it was Fortran).  He earned his Bachelor of Arts degree from the University of Waterloo and his Bachelor of Computer Science degree at the University of Windsor.  After a few years at IBM, he worked on a Master of Mathematics (Computer Science) degree at the University of Waterloo.  He decided to stay home to take care of his newborn son rather than complete that degree.  That decision cost him his career, but he would gladly make the same decision again. Warren is now retired, but he finds it hard to do nothing, so he writes web performance articles for the Monitor.Us blog.  Life is good!