2011-11-18 16 views
10

Ktoś w pracy żartobliwie wysłany e-mail z pliku HTML przeznaczonych do crash przeglądarki, która była następującaJavaScript Recursion Poprawa

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

Anyways nie wykonują świetną robotę w Chrome i rozmowy Powstało, że stworzył przyjazną konkurencję, aby zobaczyć, kto może napisać javascript, aby jak najszybciej policzyć stronę do 5.000.000.000, nie powodując, że przeglądarka przestanie reagować lub ulegać awarii.

Wpadłem na następujący fragment javascript, który ma być używany w 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> 

Dlatego, że to będzie działać tylko w Chrome to, że używam połączenia setTimeout aby uniknąć tworzenia stackoverflow w Chrome. (Chrome pozwala także na największy zestaw wywołań rekursywnych ze wszystkich przeglądarek).

Czy jest jakiś sposób, aby to policzyć szybciej? Wydaje mi się, że mogę zwiększyć kwotę, która została trochę policzona, zanim spowoduje przepełnienie (gdzieś mniej niż 100). Jedynym zastrzeżeniem jest to, że musi wyświetlać jak najwięcej liczb, jak to się liczy.


Lepsza Kod:

<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> 
  • Wykonane Ilość i elementem globabl
  • Switched wprowadzanie tekstu zamiast div
  • przeniósł aktualizacji UI aby po ustawieniu zwrotnego

Odpowiedz

2

Nie używaj .innerHTML = ... do wyświetl numer. Zgodnie z this test ustawienie właściwości elementu wejściowego jest bardziej wydajne.

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

Zamiast budowy nowej funkcji, polecam użyć Globalna/zmienne lokalne, a przechodząc odniesienie funkcję jako argument do setTimeout lub użyj setInterval w init.

  • Zamień setTimeout("countToFiveBillion()",1) dla setTimeout(countToFiveBillion,0). Objaśnienie: "countToFiveBillion()" jest nieefektywne; Najpierw łańcuch jest konwertowany na funkcję i wywoływany, a następnie następuje kolejne wywołanie funkcji. Sugerowana funkcja działa tylko po to, aby wywołać funkcję, bez tworzenia nowych. Nazywa się to również szybszym ułamkiem sekundy.
  • Podnieś limit (udało mi się zwiększyć 18701 do 20000). Po zniesieniu limitu do takiego zaokrąglonego numeru zauważyłem, że wartość counter jest aktualizowana między każdym przekroczeniem limitu czasu.
  • Naprawiono błędy w implementacji (zastąpiono .innerHTML z .value w bloku else).

odpowiedni kod:

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

+0

Nie jestem do końca pewien, jak przekazać funkcję jako odniesienie w JS woudl Po prostu zrobić this.countToFiveBillion zamiast w sposób, w jaki robię to obecnie? – msarchet

+0

Globalnie zadeklaruj zmienne, a następnie zastąp 'setTimeout (..)' przez 'setTimeout (countToFiveBillion, 1)'. –

+0

Ach tak, ma sens – msarchet

0

WebWorker przykład 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); 
    } 
} 

W razie potrzeby liczenie można podzielić na wielu pracowników.