JS - 防止“崩溃”浏览器实现中的长循环javascript

时间:2016-11-04 15:21:47

标签: javascript

我有一个长约10分钟或更长时间的循环,我想总是设置一个新的时间来避免它继续。但它不起作用。

    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()函数中它可以工作,但我不能每5秒执行一次Date() - t,类似于setInterval(Date()-t,5000)

3 个答案:

答案 0 :(得分:2)

在这种情况下,您可以考虑使用workers API。不要冻结浏览器,而是让工作在后台完成,并在完成后回调主线程。

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

答案 1 :(得分:1)

JavaScript不是多线程的。因此,我们将setInterval()视为每n ms运行一段代码(在您的示例中为5000)。但那不是真的。如果在间隔过去时脚本已经运行,那么最好的情况就是将一些代码添加到要执行的队列中 - 但是在已经运行的脚本完成之前,该队列中的任何内容都不会运行。

粗略地说,这就是为什么它不起作用,但该怎么办?好吧,如果你想在problem3()返回之前发生任何事情,那么problem3()必须以同步的方式实现它。

例如,您可以创建一个lastOutputTime变量,将其初始化为当前时间,并在每次迭代时通过for循环将当前时间与存储值进行比较。如果已经过了5秒,则输出到控制台并更新lastOutputTime

答案 2 :(得分:1)

您的算法应该改进为:

&#13;
&#13;
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));
&#13;
&#13;
&#13;

如果某些数字需要太多时间,那么将循环分解为更小的块并进行异步。但从不使用setInterval来实现此,尤其是永远不会在长循环中使用setInterval setInterval计划某些任务运行 n毫秒,因此如果您在循环中使用它,则在i次迭代后,任务将运行{{1}每i毫秒!并且n是如此有问题,因为如果任务花费的时间超过setInterval毫秒,它就会冻结浏览器。您应该使用n代替。

但是,在这种情况下,这将毫无用处。上面的算法几乎可以立即检测到setTimeout(15位)是素数。鉴于最大安全整数为304250263527209(16位),我认为您的任何数字都不会有问题。

如果你说算法需要这么长时间,可能是因为你正在尝试使用更大的数字。但要注意JS数字是64位浮点数,因此整数不能在9007199254740991之上准确表示。无论如何你都会得到错误的结果,所以甚至不要尝试计算它。

对于Project Euler#551,蛮力方法将是

&#13;
&#13;
Number.MAX_SAFE_INTEGER
&#13;
&#13;
&#13;

当然,暴力不是解决问题的适当方法。