Saturday, February 23, 2008

3 Easy Steps to Avoid JavaScript Memory Leaks

Introduction

Jack Slocum's blog used to carry an interresting post about memory leaking occuring in regular webpages. Sadly it has gone MIA.

(please note, full copyright and credits for below text belongs to Jack Slocum. Text is almost 99% verbatim from the webarchive. And even though written in first person, it was not done by me)
So, resurrected from the Web Archive I give you...

October 2, 2006 by Jack Slocum

You may not know it, but almost every site you visit that uses JavaScript is leaking memory. That may sound like an exaggeration, but it's true. Don't believe me? Leak Monitor
With this handy extension for FireFox, any time you leave a page and it leaves code pointing to JavaScript objects - it displays a popup with details about the leak. It even gives you details about the function or object that created the leak.
Leaving http://script.aculo.us/
This is probably the most common leak I see - prototype.js, line 74:

Free Image Hosting at www.ImageShack.us


The Dojo Mail example page
This one takes it to the extreme, filling two popups (look at the scrollbars!).

Free Image Hosting at www.ImageShack.us


Word Press
This one is the most irritating. Every time I edit a post in WordPress, this is what I see.

Free Image Hosting at www.ImageShack.us



Visiting all your usual sites, you will find almost every one of them is leaking memory. It's actually quite shocking that some of these sites wouldn't have some sort of testing in place to make sure this isn't happening.
-Even with all the JavaScript, example code and what not on this site, you will not have any leak alerts. I don't do anything special to avoid leaks. -

It's as simple as these 3 steps:

1. Never put anything in a DOM expando or property other than a primitive value unless you plan on cleaning it up.
This is the most important rule of all. It may seem convenient to put your JS object in a DOM expando, so you can $() and get it, but don't do it. Sure, I know what you are thinking, I am being a little paranoid. There are lots of instances where putting a JS Object in a DOM expando won't cause a leak. That's true, but there are also many that will... some which are not so easy to detect (i.e. closures). So to avoid the possibility all together, I follow this simple rule.

2. Clean up all your DOM event handlers on unload if there's a chance they could reference a DOM object.
There's no reason to manually do this when there are libraries that do it automatically. I use YAHOO.util.Event for all my event handlers, it handles this for me automagically. Other libraries (prototype, dojo, etc) have some sort of mechanism to do the same thing, although I'm not sure how effective they are. If you look at the leak images above once again, you will notice almost all of them are in event related code of those libraries.

3. Set your XMLHttpRequest onreadystatechange handlers to null when you are done with them.
I use YAHOO.util.Connect for all my XHR connections and it uses a polling mechanism instead of readstate, so I don't need to do this anymore. If you can switch to YAHOO.util.Connect (or YAHOO.ext.UpdateManager built on top of it), I'd recommend it.

Summary
Avoiding memory leaks is not that difficult. It doesn't take any special coding skills or expertise. By following the easy steps above, even a novice can write JavaScript code that is leak free. For all the big sites out there (including the new Yahoo Mail!?!?) please take the time, and fix your site so maybe I (and others) can browse the web without a memory leak on every page.

Labels:

Friday, January 25, 2008

calling an external script and passing back a result

Maxthon plugins are known to be able to use features which are normally restricted in regular embeded page script. However, even a plugin has it's limitations. One of those limitations is working with the WMI interface.


There is however a method to get around this limitation. Plugins are allowed to use most all ActiveX objects, and two of the most commonly used are the Windows Script Host and the File System Object. The solution is to place all WMI related script in an external file, separate from the regular plugin code. Then you simply use WSH to run this external script.


But what if you need access to results produced by the called script? Again there's likely more methods, but I found two methods to be most useful. If the result is only a single, numeric value, the easiest woulld be to pass the return value though the WSH exitcode.


In your plugin you then assign the result of the WSH call to a variable which you can test to have your plugin take action accordingly


testResult = oWSH.Run(<plugin.path>ExternalScript  [arguments] , 0 , false)


in the ExternalScript file (js or vbs) you then include as last execution line something like


Wscript.Quit(myReturnCode) (possible values range from 0 to 255)





Another method would be to have your external script place the results in a text file and then have your plugin parse this textfile after the call to the external script (thanks to abc@home for this last tip)

Labels: ,