我的脚本运行时是否调用了setInterval处理程序?

时间:2014-04-03 09:16:46

标签: javascript setinterval

我计划使用setInterval简单地将变量设置为false,主循环将检查该变量以停止。示例(注意:这只是一个示例,实际代码不是一个易于重构的while()循环,但实际上由一个封闭源软件生成的一个非常复杂且执行时间很长的脚本):

var running = true;
setInterval(function () {
  if (running) {
    console.log("Stopping now!");
    running = false;
  }
}, 100);

while (running) {
  // do something ...
}

然而它似乎没有起作用至少firefox掉了一个忙碌的脚本"一段时间后。上面代码的问题是什么?如果您的脚本已经运行,setInterval()可能无法运行?我无法确切地找到setInterval()的确切规范。

我需要这样的东西,因为我已经拥有巨大的(并且执行时间非常长)脚本,所以我想我会在一段时间后尝试停止它,然后使用setTimeout()让浏览器呼吸一下,然后继续:因为脚本本身确实知道它的内部状态所以它可以从任何一点继续,但实际上不能修改脚本....

如果使用setInterval是不可能的,那么有什么替代方案可以做到这一点,而不需要对" long执行"代码本身?

谢谢!

5 个答案:

答案 0 :(得分:2)

问题是Javascript是单线程的。重写你的while循环以使用setInterval本身,一切都应该有效,因为你将在每个循环结束时释放线程。

答案 1 :(得分:2)

  

如果使用setInterval是不可能的,那么有什么替代方案可以做到这一点,而不需要对" long执行"代码本身?

一种可能性是使web worker而不是尝试在UI线程上使用它。尽管人们反复这样说,但JavaScript 单线程(JavaScript,语言,对此主题保持沉默),甚至不再是浏览器。在浏览器环境中,有一个主 UI 线程,但您可以生成其他工作线程(Web worker)。工作人员和主要UI代码可以通过postMessage / onmessage进行通信。

这是一个正在运行的网络工作者的示例。此页面在UI线程上使用JavaScript来启动Web工作程序,该工作程序在单独的线程上运行。工作者运行10秒钟,忙着更新计数器(这只是为了模拟长时间运行的计算密集型进程),并每秒向UI线程发送更新:

主页:

<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Worker Example</title>
<style type="text/css">

body {
    font-family: sans-serif;
}
</style>
<meta charset="UTF-8">
</head>
<body>

<script>
(function() {
    var worker = new Worker("worker.js");
    worker.onmessage = function(e) {
        display("Worker says " + e.data);
    };
    display("Starting worker");
    worker.postMessage("start");

    function display(msg) {
        var p = document.createElement('p');
        p.innerHTML = String(msg);
        document.body.appendChild(p);
    }
})();
</script>
</body>
</html>

worker.js:

this.onmessage = function(e) {
    var counter, lastUpdate, now;

    if (e.data === "start") {
        // Loop without yeilding for 10 seconds, sending updates
        // to the UI every second.
        start = lastUpdate = Date.now();
        counter = 0;
        do {
            ++counter;
            now = Date.now();
            if (now - lastUpdate > 1000) {
                lastUpdate = now;
                this.postMessage(counter);
            }
        }
        while (now - start < 10000);
        this.postMessage("Done");
    }
};

(您不需要让工作人员等待邮件开始,但这很常见。)

答案 2 :(得分:2)

您应该考虑使用Worker或编写异步代码。

或者您可以修改代码。

var running = true;
var past = Date.now();
while (running) {
    // do heavy calculations ...



    if ((Date.now() - past) > 10) {
        running = false;
    }
}

当然,阻止循环并不是一个好主意,但我没有看到满足要求的好方法:

  

如果使用setInterval无法实现,有没有替代方案,没有任何修改在&#34;长期执行&#34;代码本身?

答案 3 :(得分:2)

JavaScript在单线程事件循环中运行。这意味着当您的代码运行时,其他代码无法运行。这就是你的回调没有被执行的原因。

您也可以通过使while(running)成为异步来解决此问题。请考虑执行以下操作:

var running = true;
var monitor = setInterval(function () {
  if (running) {
    console.log("Stopping now!");
    running = false;
    clearInterval(monitor);
  }
}, 100);

var work = setInterval(function() {
    if (running) {
        // do something
    } else {
        clearInterval(work);
    }
}, 1);

别忘了打电话给clearInterval!

答案 4 :(得分:2)

您应该在循环时使用setTimeout或setInterval。 JS在单线程中运行,因此无限循环将冻结您的浏览器。

var running = true;
setInterval(function(){
   if(running){
      console.log('Stopping now!');
      running = false;
   }
}, 100);

(function loop(){
    // Do yours loop stuff
    if( running ){
       setTimeout(loop, 0);
    }
})();