2011-11-18 24 views
10

alguien en el trabajo en broma envió un correo electrónico con un archivo html destinado a bloquear el navegador que era el siguienteJavascript recursividad Mejora

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

De todas formas no lo hace un gran trabajo de ella en Chrome y una conversación surgió que se creó una competencia amistosa para ver quién podía escribir javascript para hacer que una página cuente hasta 5,000,000,000 lo más rápido posible sin que el navegador deje de responder o se bloquee.

Se me ocurrió la siguiente pieza de javascript que se pretende usar en 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> 

La razón de que esto sólo se ejecutará en cromo es que estoy usando la llamada setTimeout para evitar crear un stackoverflow en cromo. (Chrome también te permite la pila más grande para llamadas recursivas de todos los navegadores).

¿Hay alguna manera de hacer que esto cuente más rápido? Creo que puedo aumentar la cantidad contada un poco antes de que cause un desbordamiento (en algún lugar menos de 100) La única estipulación es que tiene que mostrar la mayor cantidad de números posible.


mejorada Código:

<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> 
  • Hecho el recuento y el elemento globabl
  • Al cambiar a la entrada de texto en lugar de div
  • trasladó actualización de interfaz de usuario para después de establecer la devolución de llamada

Respuesta

2

No use .innerHTML = ... para mostrar el número. De acuerdo con this test, establecer la propiedad value de un elemento de entrada es más eficiente.

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

En lugar de construir una nueva función, recomiendo utilizar variables globales/locales, y pasando una referencia a una función como argumento para setTimeout o utiliza setInterval a init.

  • Intercambiar setTimeout("countToFiveBillion()",1) para setTimeout(countToFiveBillion,0). Explicación: "countToFiveBillion()" es ineficaz; En primer lugar, la cadena se convierte en una función y se llama, luego otra llamada de función sigue. La función sugerida ejecuta solo tiene que llamar a una función, sin crear nuevas. También se llama una fracción de segundo más rápido.
  • Eleva el límite (Pude aumentar 18701 a 20000). Después de levantar el límite a dicho número redondeado, noté que el valor counter se actualiza entre cada tiempo de espera.
  • Se corrigieron algunos errores en la implementación (se reemplazó .innerHTML con .value en el bloque else).

código relevante:

<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> 

violín: http://jsfiddle.net/KTtae/

+0

No estoy exactamente seguro de cómo pasar una función como referencia en JS, pero acabo de hacer this.countToFiveBillion en lugar de la forma en que lo estoy haciendo actualmente? – msarchet

+0

Declare globalmente las variables, luego reemplace 'setTimeout (..)' por 'setTimeout (countToFiveBillion, 1)'. –

+0

Ah sí, tiene sentido – msarchet

0

ejemplo Webworker, index.html

<!DOCTYPE HTML> 
<html> 
<head> 
    <title>5 billion</title> 
</head> 
<body> 
    <input type="text" id="counter" value="0" /> 
    <script type="text/javascript" charset="utf-8"> 
     var 
      iCounter = document.getElementById('counter') 
      , counter = new Worker('worker.js'); 

     iCounter.value = 0; 
     counter.addEventListener('message', function (e) { 
      iCounter.value = e.data; 
     }, false); 
    </script> 
</body> 
</html> 

worker.js:

for (var i = 0; i < 5e9; i++) { 
    if (i % 18701 === 0) { 
     postMessage(i); 
    } 
} 

El recuento se puede dividir en varios trabajadores si es necesario.