Showing posts with label javascript tips. Show all posts
Showing posts with label javascript tips. Show all posts

Wednesday, October 29, 2008

JavaScript and memory leaks

Credits: This tutorial is written by Volkan. He runs the site Sarmal.com, a bilingual site featuring all his work, products, services, and up-to-date profile information in English and Turkish.

If you are developing client-side re-usable scripting objects, sooner or later you will find yourself spotting out memory leaks. Chances are that your browser will suck memory like a sponge and you will hardly be able to find a reason why your lovely DHTML navigation's responsiveness decreases severely after visiting a couple of pages within your site.

A Microsoft developer Justing Rogers has described IE leak patterns in his excellent article.

In this article, we will review those patterns from a slightly different perspective and support it with diagrams and memory utilization graphs. We will also introduce several subtler leak scenarios. Before we begin, I strongly recommend you to read that article if you have not already read.

Why does the memory leak?

The problem of memory leakage is not just limited to Internet Explorer. Almost any browser (including but not limited to Mozilla, Netscape and Opera) will leak memory if you provide adequate conditions (and it is not that hard to do so, as we will see shortly). But (in my humble opinion, ymmv etc.) Internet Explorer is the king of leakers.

Don't get me wrong. I do not belong to the crowd yelling "Hey IE has memory leaks, checkout this new tool [link-to-tool] and see for yourself". Let us discuss how crappy Internet Explorer is and cover up all the flaws in other browsers".

Each browser has its own strengths and weaknesses. For instance, Mozilla consumes too much of memory at initial boot, it is not good in string and array operations; Opera may crash if you write a ridiculously complex DHTML script which confuses its rendering engine.

Although we will be focusing on the memory leaking situations in Internet Explorer, this discussion is equally applicable to other browsers.

A simple beginning


[Exhibit 1 - Memory leaking insert due to inline script]

<html>
<head>
<script type="text/javascript">
function LeakMemory(){
var parentDiv =
document.createElement("<div onclick='foo()'>");

parentDiv.bigString = new Array(1000).join(
new Array(2000).join("XXXXX"));
}
</script>
</head>
<body>
<input type="button"
value="Memory Leaking Insert" onclick="LeakMemory()" />
</body>
</html>


The first assignment parentDiv=document.createElement(...); will create a div element and create a temporary scope for it where the scripting object resides. The second assignment parentDiv.bigString=... attaches a large object to parentDiv. When LeakMemory() method is called, a DOM element will be created within the scope of this function, a very large object will be attached to it as a member property and the DOM element will be de-allocated and removed from memory as soon as the function exits, since it is an object created within the local scope of the function.

When you run the example and click the button a few times, your memory graph will probably look like this:



Increasing the frequency



No visible leak huh? What if we do this a few hundred times instead of twenty, or a few thousand times? Will it be the same? The following code calls the assignment over and over again to accomplish this goal:

[Exhibit 2 - Memory leaking insert (frequency increased) ]

<html>
<head>
<script type="text/javascript">
function LeakMemory(){
for(i = 0; i < 5000; i++){
var parentDiv =
document.createElement("<div onClick='foo()'>");
}
}
</script>
</head>
<body>
<input type="button"
value="Memory Leaking Insert" onclick="LeakMemory()" />
</body>
</html>
And here follows the corresponding graph:




The ramp in the memory usage indicates leak in memory. The horizontal line (the last 20 seconds) at the end of the ramp is the memory after refreshing the page and loading another (about:blank) page. This shows that the leak is an actual leak and not a pseudo leak. The memory will not be reclaimed unless the browser window and other dependant windows if any are closed.

Assume you have a dozen pages that have similar leakage graph. After a few hours, you may want to restart your browser (or even your PC) because it just stops responding. The naughty browser is eating up all your resources. However, this is an extreme case because Windows will increase the virtual memory size as soon as your memory consumption reaches a certain level.

This is not a pretty scenario. Your client/boss will not be very happy, if they discover such a situation in the middle of a product showcase/training/demo.

A careful eye may have caught that there is no bigString in the second example. This means that the leak is merely because of the internal scripting object (i.e. the anonymous script onclick='foo()'). This script was not deallocated properly. This caused memory leak at each iteration. To prove our thesis let us run a slightly different test case:

[Exhibit 3 - Leak test without inline script attached]

<html>
<head>
<script type="text/javascript">
function LeakMemory(){
for(i = 0; i < 50000; i++){
var parentDiv =
document.createElement("div");
}
}
</script>
</head>
<body>
<input type="button"
value="Memory Leaking Insert" onclick="LeakMemory()" />
</body>
</html>


And here follows the corresponding memory graph:







JavaScript and memory leaks

Credits: This tutorial is written by Volkan. He runs the site Sarmal.com, a bilingual site featuring all his work, products, services, and up-to-date profile information in English and Turkish.

If you are developing client-side re-usable scripting objects, sooner or later you will find yourself spotting out memory leaks. Chances are that your browser will suck memory like a sponge and you will hardly be able to find a reason why your lovely DHTML navigation's responsiveness decreases severely after visiting a couple of pages within your site.

A Microsoft developer Justing Rogers has described IE leak patterns in his excellent article.

In this article, we will review those patterns from a slightly different perspective and support it with diagrams and memory utilization graphs. We will also introduce several subtler leak scenarios. Before we begin, I strongly recommend you to read that article if you have not already read.
Why does the memory leak?

The problem of memory leakage is not just limited to Internet Explorer. Almost any browser (including but not limited to Mozilla, Netscape and Opera) will leak memory if you provide adequate conditions (and it is not that hard to do so, as we will see shortly). But (in my humble opinion, ymmv etc.) Internet Explorer is the king of leakers.

Don't get me wrong. I do not belong to the crowd yelling "Hey IE has memory leaks, checkout this new tool [link-to-tool] and see for yourself". Let us discuss how crappy Internet Explorer is and cover up all the flaws in other browsers".

Each browser has its own strengths and weaknesses. For instance, Mozilla consumes too much of memory at initial boot, it is not good in string and array operations; Opera may crash if you write a ridiculously complex DHTML script which confuses its rendering engine.

Although we will be focusing on the memory leaking situations in Internet Explorer, this discussion is equally applicable to other browsers.
A simple beginning

Let us begin with a simple example:

<html>
<head>
<script type="text/javascript">
function LeakMemory(){
var parentDiv =
document.createElement("<div onclick='foo()'>");

parentDiv.bigString = new Array(1000).join(
new Array(2000).join("XXXXX"));
}
</script>
</head>
<body>
<input type="button"
value="Memory Leaking Insert" onclick="LeakMemory()" />
</body>
</html>

The first assignment parentDiv=document.createElement(...); will create a div element and create a temporary scope for it where the scripting object resides. The second assignment parentDiv.bigString=... attaches a large object to parentDiv. When LeakMemory() method is called, a DOM element will be created within the scope of this function, a very large object will be attached to it as a member property and the DOM element will be de-allocated and removed from memory as soon as the function exits, since it is an object created within the local scope of the function.

When you run the example and click the button a few times, your memory graph will probably look like this:

Increasing the frequency

No visible leak huh? What if we do this a few hundred times instead of twenty, or a few thousand times? Will it be the same? The following code calls the assignment over and over again to accomplish this goal:

[Exhibit 2 - Memory leaking insert (frequency increased) ]

<html>
<head>
<script type="text/javascript">
function LeakMemory(){
for(i = 0; i < 5000; i++){
var parentDiv =
document.createElement("<div onClick='foo()'>");
}
}
</script>
</head>
<body>
<input type="button"
value="Memory Leaking Insert" onclick="LeakMemory()" />
</body>
</html>


And here follows the corresponding graph:

The ramp in the memory usage indicates leak in memory. The horizontal line (the last 20 seconds) at the end of the ramp is the memory after refreshing the page and loading another (about:blank) page. This shows that the leak is an actual leak and not a pseudo leak. The memory will not be reclaimed unless the browser window and other dependant windows if any are closed.

Assume you have a dozen pages that have similar leakage graph. After a few hours, you may want to restart your browser (or even your PC) because it just stops responding. The naughty browser is eating up all your resources. However, this is an extreme case because Windows will increase the virtual memory size as soon as your memory consumption reaches a certain level.

This is not a pretty scenario. Your client/boss will not be very happy, if they discover such a situation in the middle of a product showcase/training/demo.

A careful eye may have caught that there is no bigString in the second example. This means that the leak is merely because of the internal scripting object (i.e. the anonymous script onclick='foo()'). This script was not deallocated properly. This caused memory leak at each iteration. To prove our thesis let us run a slightly different test case:

[Exhibit 3 - Leak test without inline script attached]

<html>
<head>
<script type="text/javascript">
function LeakMemory(){
for(i = 0; i < 50000; i++){
var parentDiv =
document.createElement("div");
}
}
</script>
</head>
<body>
<input type="button"
value="Memory Leaking Insert" onclick="LeakMemory()" />
</body>
</html>


And here follows the corresponding memory graph:

As you can see, we have done fifty thousand iterations instead of 5000, and still the memory usage is flat (i.e. no leaks). The slight ramp is due to some other process in my PC.

Let us change our code in a more standard and somewhat unobtrusive manner (not the correct term here, but can't find a better one) without embedded inline scripts and re-test it.

Article Source

Read More......

Dynamically removing/ replacing an external JavaScript or CSS file

Any external JavaScript
or CSS file, whether added manually or dynamically, can be removed from the page. The end result may not be fully what you had in mind, however. I'll talk about this a little later.

Dynamically removing an external JavaScript
or CSS file


To remove an external JavaScript or CSS file from a page, the key is to hunt them down first by traversing the DOM, then call DOM's removeChild() method to do the hit job. A generic approach is to identify an external file to remove based on its file name, though there are certainly other approaches, such as by CSS class name. With that in mind, the below function removes any external JavaScript or CSS file based on the file name entered:

function removejscssfile(filename, filetype){
var targetelement=(filetype=="js")? "script" : (filetype=="css")? "link" : "none" //determine element type to create nodelist from
var targetattr=(filetype=="js")? "src" : (filetype=="css")? "href" : "none" //determine corresponding attribute to test for
var allsuspects=document.getElementsByTagName(targetelement)
for (var i=allsuspects.length; i>=0; i--){ //search backwards within nodelist for matching elements to remove
if (allsuspects[i] && allsuspects[i].getAttribute(targetattr)!=null && allsuspects[i].getAttribute(targetattr).indexOf(filename)!=-1)
allsuspects[i].parentNode.removeChild(allsuspects[i]) //remove element by calling parentNode.removeChild()
}
}

removejscssfile("somescript.js", "js") //remove all occurences of "somescript.js" on page
removejscssfile("somestyle.css", "css") //remove all occurences "somestyle.css" on page


The function starts out by creating a collection out of either all "SCRIPT" or "LINK" elements on the page depending on the desired file type to remove. The corresponding attribute to look at also changes accordingly ("src" or "href" attribute). Then, the function sets out to loop through the gathered elements backwards to see if any of them match the name of the file that should be removed. There's a reason for the reversed direction- if/whenever an identified element is deleted, the collection collapses by one element each time, and to continue to cycle through the new collection correctly, reversing the direction does the trick (it may encounter undefined elements, hence the first check for allsuspects[i] in the if statement). Now, to delete the identified element, the DOM method parentNode.removeChild() is called on it.

So what actually happens when you remove an external JavaScript or CSS file? Perhaps not entirely what you would expect actually. In the case of JavaScript, while the element is removed from the document tree, any code loaded as part of the external JavaScript file remains in the browser's memory. That is to say, you can still access variables, functions etc that were added when the external file first loaded (at least in IE7 and Firefox 2.x). If you're looking to reclaim browser memory by removing an external JavaScript, don't rely on this operation to do all your work. With external CSS files, when you remove a file, the document does reflow to take into account the removed CSS rules, but unfortunately, not in IE7 (Firefox 2.x and Opera 9 do).

Dynamically replacing an external JavaScript or CSS file


Replacing an external JavaScript or CSS file isn't much different than removing one as far as the process goes. Instead of calling parentNode.removeChild(), you'll be using parentNode.replaceChild() to do the bidding instead:

function createjscssfile(filename, filetype){
if (filetype=="js"){ //if filename is a external JavaScript file
var fileref=document.createElement('script')
fileref.setAttribute("type","text/javascript")
fileref.setAttribute("src", filename)
}
else if (filetype=="css"){ //if filename is an external CSS file
var fileref=document.createElement("link")
fileref.setAttribute("rel", "stylesheet")
fileref.setAttribute("type", "text/css")
fileref.setAttribute("href", filename)
}
return fileref
}

function replacejscssfile(oldfilename, newfilename, filetype){
var targetelement=(filetype=="js")? "script" : (filetype=="css")? "link" : "none" //determine element type to create nodelist using
var targetattr=(filetype=="js")? "src" : (filetype=="css")? "href" : "none" //determine corresponding attribute to test for
var allsuspects=document.getElementsByTagName(targetelement)
for (var i=allsuspects.length; i>=0; i--){ //search backwards within nodelist for matching elements to remove
if (allsuspects[i] && allsuspects[i].getAttribute(targetattr)!=null && allsuspects[i].getAttribute(targetattr).indexOf(oldfilename)!=-1){
var newelement=createjscssfile(newfilename, filetype)
allsuspects[i].parentNode.replaceChild(newelement, allsuspects[i])
}
}
}

replacejscssfile("oldscript.js", "newscript.js", "js") //Replace all occurences of "oldscript.js" with "newscript.js"
replacejscssfile("oldstyle.css", "newstyle", "css") //Replace all occurences "oldstyle.css" with "newstyle.css"


Notice the helper function createjscssfile(), which is essentially just a duplicate of loadjscssfile() as seen on the previous page, but modified to return the newly created element instead of actually adding it to the page. It comes in handy when parentNode.replaceChild() is called in replacejscssfile() to replace the old element with the new. Some good news here- when you replace one external CSS file with another, all browsers, including IE7, will reflow the document automatically to take into account the new file's CSS rules.

Conclusion


So when is all this useful? Well, in today's world of Ajax
and ever larger web applications
, being able to load accompanying JavaScript/ CSS files asynchronously and on demand is not only handy, but in some cases, necessary. Have fun finding out what they are, or implementing the technique. :)

Article Source

Read More......

Dynamically loading an external JavaScript or CSS file

The conventional way to loading external JavaScript (ie: .js) and CSS (ie: .css) files on a page is to stick a reference to them in the HEAD section of your page, for example:

<head>
<script type="text/javascript" src="myscript.js"></script>
<link rel="stylesheet" type="text/css" href="main.css" />
</head>


Files that are called this way are added to the page as they are encountered in the page's source, or synchronously. For the most part, this setup meets our needs just fine, though in the world of synchronous Ajax design patterns, the ability to also fire up JavaScript/ CSS on demand
is becoming more and more handy. In this tutorial, lets see how it's done.

Dynamically loading external JavaScript and CSS files

To load a .js or .css file dynamically, in a nutshell, it means using DOM methods to first create a swanky new "SCRIPT" or "LINK" element, assign it the appropriate attributes, and finally, use element.appendChild() to add the element to the desired location within the document tree. It sounds a lot more fancy than it really is. Lets see how it all comes together:

function loadjscssfile(filename, filetype){
if (filetype=="js"){ //if filename is a external JavaScript file
var fileref=document.createElement('script')
fileref.setAttribute("type","text/javascript")
fileref.setAttribute("src", filename)
}
else if (filetype=="css"){ //if filename is an external CSS file
var fileref=document.createElement("link")
fileref.setAttribute("rel", "stylesheet")
fileref.setAttribute("type", "text/css")
fileref.setAttribute("href", filename)
}
if (typeof fileref!="undefined")
document.getElementsByTagName("head")[0].appendChild(fileref)
}

loadjscssfile("myscript.js", "js") //dynamically load and add this .js file
loadjscssfile("javascript.php", "js") //dynamically load "javascript.php" as a JavaScript file
loadjscssfile("mystyle.css", "css") ////dynamically load and add this .css file


Since external JavaScript and CSS files can technically end with any custom file extension (ie: "javascript.php"), the function parameter "filetype" lets you tell the script what file type to expect before loading. After that, the function sets out to create the element using the appropriate DOM methods, assign it the proper attributes, and finally, add it to the end of the HEAD section. Now, where the created file gets added is worth elaborating on:

document.getElementsByTagName("head")[0].appendChild(fileref)


By referencing the HEAD element of the page first and then calling appendChild(), this means the newly created element is added to the very end of the HEAD tag. Furthermore, you should be aware that no existing element is harmed in the adding of the new element- that is to say, if you call loadjscssfile("myscript.js", "js") twice, you now end up with two new "SCRIPT" elements both pointing to the same JavaScript file. This is problematic only from an efficiency standpoint, as you'll be adding redundant elements to the page and using unnecessary browser memory in the process. A simple way to prevent the same file from being added more than once is to keep track of the files added by loadjscssfile(), and only load a file if it's new:

var filesadded="" //list of files already added

function checkloadjscssfile(filename, filetype){
if (filesadded.indexOf("["+filename+"]")==-1){
loadjscssfile(filename, filetype)
filesadded+="["+filename+"]" //List of files added in the form "[filename1],[filename2],etc"
}
else
alert("file already added!")
}

checkloadjscssfile("myscript.js", "js") //success
checkloadjscssfile("myscript.js", "js") //redundant file, so file not added


Here I'm just crudely detecting to see if a file that's set to be added already exists within a list of added files' names stored in variable filesadded before deciding whether to proceed or not.

Ok, moving on, sometimes the situation may require that you actually remove or replace an added .js or .css file. Lets see how that's done next.

Article Source

Read More......

Friday, July 4, 2008

Redirecting your visitors to the preferred form of your URL using JavaScript

Do you have multiple entrances to your site and looking for a client-side solution that can redirect your visitors to the preferred entrance?

For example, you may have multiple domain names pointing to the same site -- domain_a.com, domain_b.com and domain_c.com.

Do you have multiple entrances to your site and looking for a client-side solution that can redirect your visitors to the preferred entrance?

For example, you may have multiple domain names pointing to the same site -- domain_a.com, domain_b.com and domain_c.com. Although you want to keep all of your domains either because you want to reserve those names, because your marketing department convinced you that having multiple names pointing to the same site will attract more visitors or some other reason, you may prefer that the visitors end up at the same domain. You may want to redirect visitors from domain_b.com and domain_c.com to domain_a.com for example.

Following is a client-side solution to redirecting visitors to your preferred domain. Simply copy and paste it on to your home page just below the tag.

<script type="text/javascript" language="JavaScript">
<!--
if( -1 == location.href.
toLowerCase().
indexOf('domain_a.com') )
{
location.href = 'http://domain_a.com';
}
// -->
</script>

bove code will check if domain_a.com is a part of the current URL. If not, it will automatically redirect the visitor to http://domain_a.com. One of the advantages is that this code will work even if you have a single version of your home page that has multiple domain names pointing to it.

Of course you can modify the same code to redirect to a specific page URL as well.

NOTE : Be sure to use only the required portion of your URL and to enter it in lowercase inside the function "indexOf()". If your complete URL is http://www.mycompany.com/mypage.html, but you can get to the same page using just mycompany.com/mypage.html, use the latter version of the URL. On the other hand, use the full URL for location.href.

The following code will redirect visitors to http://www.mycompany.com/mypage.html only if mycompany.com/mypage.html is not a part of the URL they typed:

<script type="text/javascript" language="JavaScript">
<!--
if( -1 == location.href.
toLowerCase().
indexOf('mycompany.com/mypage.html') )
{
location.href =
'http://www.mycompany.com/mypage.html';
}
// -->
</script>

If you run your own web server, have unique IP addresses for your multiple domains or your web space provider is able to redirect visitors otherwise, you maybe able to implement a server-side solution to redirect visitors instead.

Read More......

How can browser specific content be delivered using JavaScript?

If you have a need to deliver browser specific web pages and if you don't have a server-side script to do this with, take a look at the following HTML/JavaScript code:

<SCRIPT LANGUAGE="JavaScript" TYPE="text/javascript">
<!--
if( -1 != navigator.userAgent.
indexOf ("AOL") )
{
// load America Online version
location.href="aol.htm";
}
else
if( -1 != navigator.userAgent.
indexOf ("MSIE") )
{
// load Microsoft Internet
// Explorer version
location.href="msie.htm";
}
else
if( -1 != navigator.userAgent.
indexOf ("Mozilla") )
{
// load Netscape version
location.href="netscape.htm";
}
else
{
// load other version
location.href="other.htm";
}
-->
</SCRIPT>


You can simply plug in above tags after replacing "netscape.htm" with the URL to your Netscape specific page, "other.htm" with your generic page's URL, "MSIE.htm" with the Microsoft Internet Explorer version of the page, etc.

Read More......

How to hide JavaScript code from non-JavaScript enabled browsers

Its easy to hi Javascript from Non-javascript based browsers..just use the script like done below :

<SCRIPT LANGUAGE="JavaScript" TYPE="text/javascript">

<!--

... your JavaScript code goes here ...
... this code will be hidden from ...
... non-JavaScript enabled browsers ...

//-->

</SCRIPT>

Read More......
Your Ad Here
Reader's kind attention....The articles contained in this blog can be taken from other web sites, as the main intention of this blog is to let people get all sides of the web technologies under the single roof..so if any one finds duplication or copy of your articles in this blog and if you want that to be removed from this ..kindly inform me and i will remove it...alternatively if you want me to link back to your site with the article...that can also be done...

Thanks,
Webnology Blog Administrator
 

blogger templates