Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript Recursion Improvement

Someone at work jokingly sent out an email with a html file intended to crash your browser that was the following

<html>
<script type="text/javascript">
function crash(){
  for(i=0;i<5000000001;i++){
    document.write(i);
  }
}
</script>
<body onload="crash();">
</body>
</html>

Anyways it doesn't do a great job of it in Chrome and a conversation arose that it created a friendly competition to see who could write javascript to make a page count to 5,000,000,000 as quickly as possible without causing the browser to become unresponsive or crash.

I came up with the following piece of javascript that is intended to be used in Chrome.

<html>
<script type="text/javascript">
function countToFiveBillion(counter, num){
  if(num < 5000000000)
  {
    num++;
    if(num % 18700 == 0){
      counter.innerHTML = num;
      setTimeout(function() {countToFiveBillion(counter, num)}, 1);
    } else {
      countToFiveBillion(counter, num);
    }
  }
}
function initiateCountDown()
{
   var counter = document.getElementById("counter");
   var num = +counter.innerHTML;
   countToFiveBillion(counter, num);
}
</script>
<body onload="initiateCountDown();">
<div id="counter">0</div>
</body>

</html>

The reason that this will only run in chrome is that I'm using the setTimeout call to avoid creating a stackoverflow in chrome. (Chrome also allows you the largest stack for recursive calls out of all of the browsers).

Is there any way for me to make this count any quicker? I think that I can increase the amount counted a little before it causes an overflow (somewhere less than 100 though) The only stipulation is that is has to display as many numbers as possible as it counts.


Improved Code:

<html>
<script type="text/javascript">
var counter;
var num = 0;
function countToFiveBillion(){
    if(num < 5000000000)
    {
    num++;
    if(num % 18701 == 0){
        setTimeout("countToFiveBillion()", 1);
            counter.value = num;
        } else {
        countToFiveBillion();
    }
    } else {
        counter.value = "number greater than 5 Billion";
    }
}
function initiateCountDown()
{
   counter = document.getElementById('counter');
   countToFiveBillion();
}
</script>
<body onload="initiateCountDown();">
    <input type="text" id="counter" value="0" />
</body>

</html>
  • Made count and element globabl
  • Switched to text input instead of div
  • moved update UI to after setting the callback
like image 258
msarchet Avatar asked Nov 18 '11 16:11

msarchet


1 Answers

Don't use .innerHTML = ... to display the number. According to this test, setting the value property of an input element is more efficient.

<input type="text" id="counter" value="0" />

Instead of constructing a new function, I recommend to use global / local variables, and passing a function reference as an argument to setTimeout, or use setInterval at init.

  • Swap setTimeout("countToFiveBillion()",1) for setTimeout(countToFiveBillion,0). Explanation: "countToFiveBillion()" is inefficient; First, the string gets converted to a function and called, then another function call follows. The suggested function runs only has to call a function, without creating new ones. It's also called a split second faster.
  • Lift the limit (I was able to increase 18701 to 20000). After lifting the limit to such a rounded number, I noticed that the counter value is updated between each time-out.
  • Fixed some errors in the implementation (replaced .innerHTML with .value at the else-block).

Relevant code:

<input type="text" id="counter" />
<script>
var counter, num = 0;
function countToFiveBillion(){
    if(num < 5e9)
    {
        if(++num % 18701 == 0){
            setTimeout(countToFiveBillion, 0);
            counter.value = num;
        } else {
            countToFiveBillion();
        }
    } else {
        counter.value = "number greater than 5 Billion";
    }
}
function initiateCountDown(){
    counter = document.getElementById('counter');
    counter.value = num; //Init, show that the script is 
    countToFiveBillion();
}
window.onload = initiateCountDown;
</script>

Fiddle: http://jsfiddle.net/KTtae/

like image 91
Rob W Avatar answered Nov 15 '22 19:11

Rob W