簡體   English   中英

我的腳本運行時是否調用了setInterval處理程序?

[英]Is setInterval handler called while my script running?

我計划使用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是不可能的,那么在“長期執行”代碼本身中是否有任何替代方法可以替代它?

謝謝!

問題是Javascript是單線程的。 重寫你的while循環以使用setInterval本身,一切都應該工作,因為你將在每個循環結束時釋放線程。

如果使用setInterval是不可能的,那么在“長期執行”代碼本身中是否有任何替代方法可以替代它?

一種可能性是使其成為Web工作者而不是嘗試在UI線程上使用它。 盡管人們反復這樣說,但JavaScript 並不是單線程的(JavaScript,語言,在主題上是靜默的),甚至不再是瀏覽器。 在瀏覽器環境中,有一個主UI線程,但您可以生成其他工作線程(Web worker)。 工作人員和主UI代碼可以通過postMessage / onmessage進行通信。

這是一個正在運行的Web工作者的示例。 此頁面在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");
    }
};

(您不需要讓工作人員等待消息啟動,但這很常見。)

您應該考慮使用Worker或編寫異步代碼。

或者您可以修改您的代碼。

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



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

當然,阻塞循環並不是一個好主意,但我沒有看到滿足要求的好方法:

如果這是不可能的setInterval,沒有任何替代方案, 而無需在“長期執行”代碼本身進行任何修改

JavaScript在單線程事件循環中運行。 這意味着當您的代碼運行時,其他代碼無法運行。 這就是你的回調沒有被執行的原因。

你可以通過使你的while(運行)異步來解決這個問題。 考慮執行以下操作:

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!

你應該在循環時使用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);
    }
})();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM