2016-11-04 71 views
0

我有一個長的循環,可能需要10分鐘或更長時間,並且我想始終設置一個新的時間以避免它繼續。但它不起作用。JS - 防止從「崩潰」瀏覽器執行長循環javascript

function problem3(){ 
       var img = document.getElementById('p_3'); 
       img.style.display = img.style.display === 'block' ? 'none' : 'block'; 
       var number=600851475143; 
       var t = new Date(); 
       for(var i=3;i*i<=number;i+=2){ 
        if(isPrime(i) && number%i==0){ 
         var maxPrime = i; 
        } 
        setInterval(function(){time(t)},5000); 
       } 
       document.getElementById("p3").innerHTML = 'Il più grande divisiore primo di <span>'+number+"</span> è <span>" + maxPrime+"</span>"; 
    } 
function time(t){ 
      return console.log(Date() - t); 
     } 

如果我把console.log(Date() - t);在它的工作原理problem3()函數,但我不能做的日期() - T的每5秒,像setInterval(Date()-t,5000)

+1

您是否想要獲得最大素數?然後,當你找到一個主要因素時,除以數字。 – Oriol

+0

是的,我做了:'if(isPrime(i)&& number%i == 0)',但是這個代碼是在JS中的,因爲chrome瀏覽器總是字符串,所以我想給它更多的時間..UPDATE:好吧,我想你想說什麼我 – Teshtek

+1

我的意思是'數字/ =我',直到'數字%我!= 0'。如果'number'具有各種主要因素,它將使循環更短。 – Oriol

回答

1

JavaScript是不是多線程。所以我們認爲setInterval()每隔n ms(在你的例子中爲5000)運行一段代碼。但這並不完全正確。如果在時間間隔內已經有腳本運行,那麼可能發生的最好情況就是將一些代碼添加到要執行的隊列中,但是直到已經運行的腳本完成後,該隊列中的任何內容纔會運行。

所以粗略地說,這就是爲什麼它不工作,但該怎麼辦?那麼,如果你想在problem3()返回之前發生任何事情,那麼problem3()就必須以同步的方式發生。

例如,您可以創建一個lastOutputTime變量,將其初始化爲當前時間,並且在for循環的每次迭代中將當前時間與存儲值進行比較。如果5秒過去了,輸出到控制檯並更新lastOutputTime

+0

完美我理解!無論如何,我發現到我的代碼函數的錯誤,在這裏:'time(t){return。console.log(Date() - t); ''我在'Date()'之前忘記** new **,所以現在'time(t){return Date() - t); }'作品 – Teshtek

2

這種情況下,您可能會考慮使用工作程序API。不要凍結瀏覽器,而應該在後臺完成作業,並在完成後回調主線程。

https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API

+0

是的,但我需要一個通用的解決方案。我的意思是** Web工作人員不能與DOM交互** – Teshtek

+0

這是有意的。當結果出現時,工作者將消息傳遞迴UI線程,後者更新DOM。它並不比截取click事件複雜,並且避免了在線程之間共享非同步數據時會出現的大部分混亂。 –

1

你的算法進行改進,這樣的事:

function maxPrimeFactor(number) { 
 
    if (number == 0 || !Number.isInteger(number) || 
 
     number > Number.MAX_SAFE_INTEGER) return NaN; 
 
    number = Math.abs(number); 
 
    while(number % 2 == 0) number /= 2; 
 
    for (var i = 3; i * i <= number; i += 2) { 
 
    while(number % i == 0) number /= i; 
 
    } 
 
    return number; 
 
} 
 
var number = 600851475143; 
 
console.log('maxPrimeFactor(' + number + ') == ' + maxPrimeFactor(number));

如果您需要太多時間的一些數字,然後打破循環成小塊,並asynchronize。但從來沒有使用setInterval,特別是永遠不會使用setInterval長循環內setInterval安排一些任務運行n毫秒,所以如果您在循環中使用它,在迭代i之後,任務將每n毫秒運行i!而setInterval是如此的有問題,因爲它可以凍結瀏覽器,如果任務需要超過n毫秒。您應該改用setTimeout

然而,在這種情況下,這將是無用的。上述算法幾乎可以立即檢測出304250263527209(15位數字)是否爲主數據。鑑於最大安全整數是9007199254740991(16位數字),我不認爲你會遇到任何問題。

如果你說這個算法需要這麼長時間,那可能是因爲你用更大的數字來嘗試它。但要注意JS數字是64位浮點數,因此整數不能準確地表示在Number.MAX_SAFE_INTEGER之上。反正你會得到一個錯誤的結果,所以甚至不要去計算這個結果。

在項目歐拉#551的情況下,蠻力的方法是

function sumOfDigits(n) { 
 
    var sum = 0; 
 
    while(n != 0) { 
 
    sum += n % 10; 
 
    n = Math.floor(n/10); 
 
    } 
 
    return sum; 
 
} 
 
function sumDigitsSeq(n) { 
 
    return new Promise(function(resolve) { 
 
    var i = 1; 
 
    var chunkSize = 1e5; 
 
    var sum = 1; 
 
    (function chunk() { 
 
     chunkSize = Math.min(chunkSize, n-i); 
 
     for (var j=0; j<chunkSize; ++j, ++i) { 
 
     sum += sumOfDigits(sum); 
 
     } 
 
     if (i >= n) return resolve(sum); 
 
     console.log('Please wait. sumDigitsSeq(' + i + ') == ' + sum); 
 
     setTimeout(chunk, 60); 
 
    })(); 
 
    }); 
 
} 
 
var number = 1e6; 
 
sumDigitsSeq(number).then(function(result) { 
 
    console.log('Done! sumDigitsSeq(' + number + ') == ' + result); 
 
});

當然蠻力的是不解決問題的適當方法。

+0

這是一個非常好的算法解決方案,但我只想處理線程,因爲我該如何做這個[EULER PROBLEM](https://projecteuler.net/problem=551)....'var max = 1e +15; \t \t \t var sum = new BigNumber(1); \t \t \t爲(VAR I = 1; I Teshtek

+0

@Teshtek無論如何,我不認爲你應該使用蠻力來解決這些歐拉問題。你可能應該使用數學來找到一個簡單的公式。 – Oriol

+0

是的,有數學技巧,但我只想學習如何處理長循環或大任務,這需要很多時間,在JS – Teshtek