Wrong use of timers in Javascript causes Browser CPU Usage to Increase

I was investigating an issue on a site. Under certain conditions, the web page was becoming unresponsive and CPU usage on machine was mounting to 100% and making the machine unusable. I could not reproduce the problem easily. After asking few more questions to user, I found out that it was happening when the user came to the page after clicking on the link from a certain page. And there was another issue being seen some users. If they leave the page open all night long, by morning time the memory usage in the browser had increased to more than 150MB, CPU usage was close to 50% and machine was very sluggish. After they killed the browser instance, the machine became normal.

After investigating the page's implementation, I saw that there was lot of asynchronous (AJAX) type of implementation. The page was getting multiple pieces of response from server at different interval of times. After looking at the javascript on the page, I saw there were lot of usage of setTimeout and setInterval functions to do things like, clock ticks, requesting data from server etc. I noticed that in one work flow there was following piece of code.


function doTickTock(){
  myTimer = setTimeout("doTickTock()", 1000);
}

This code was calling the method every second. There were couple of issues with this piece of code. I will discuss those little later. I created a small page with few lines of javascript to simulate the code. Here is that piece of code.


<script type="text/javascript">
function clockTick1() {
 document.getElementById("clientClockSpan").innerHTML = new Date().toTimeString();
 clockTimer = setInterval("clockTick1()", 1000);
}

function clockTick2() {
 document.getElementById("clientClockSpan").innerHTML = new Date().toTimeString();
 clockTimer = setTimeout("clockTick2()", 1000);
}


When I used clockTick1() method, my machine's CPU usage mounted to 75% in about 15 seconds and then machine became so sluggish that I had to kill it. But when I used clockTick2() method, i did not see any sluggish behavior. To understand this behavior, you should know the difference between setInterval and setTimeout methods. setInterval calls the function passed in as first parameter after every interval of time that is passed in as second parameter. So it is setting up a timer that will tick at fixed interval. Where as setTimeout only calls the method once after the set interval of time. So when I used clockTick1, every second it was calling the method. But there was one bad thing it was doing. It generated another timer to call the same method every second. So you the number of active timers were increasing exponentially. And they brought the browser to halt. What this piece of code did not do was to call clearInterval to destroy the previous timer before creating new one. So the code should have looked like as below.


function clockTick1() {
 document.getElementById("clientClockSpan").innerHTML = new Date().toTimeString();
 if (clockTimer != null){
   clearInterval(clockTimer);
   clockTimer = null;
 }
 clockTimer = setInterval("clockTick1()", 1000);
}

You will notice that I followed the best practices of setting timer object to null to dispose it off. If you do not do that, the garbage collector will reclaim these unused timers but it will do when its runs next time. But for that period of time, you may observe increased usage of memory by browser along with high usage of object handles. Well usage of handles is important because if they are not reclaimed quickly your browser may start becoming sluggish. So treat these timers very carefully.

Even in the function where setTimeout is being used, make it a practice to clear timer object before setting new one up.

comments powered by Disqus

Search

Social

Weather

7.2 °C / 45.0 °F

weather conditions Clouds

Monthly Posts

Blog Tags