2017-03-13 39 views
2

我是一個JavaScript新手,我試圖通過setIntervalsetTimeout來實現併發操作。setInterval和setTimeout的併發操作

我想要達到的目標,實際發生的事情和我期望發生的事情最好用下面的代碼解釋。

var myVar = setInterval(function() { 
 
    myTimer() 
 
}, 1000); 
 

 
function myTimer() { 
 
    var d = new Date(); 
 
    var t = d.toLocaleTimeString(); 
 
    document.getElementById("demo").innerHTML = t; 
 
} 
 

 
for (var i = 0; i < 100; i++) { 
 
    setTimeout(function() { 
 
    console.log("log " + i); 
 
    }, 3000); 
 
}
<p>A script on this page starts this clock:</p> 
 
<p id="demo"></p>

我的期望爲主導setInterval,是函數myTimer,每次執行第二個獨立的事後會發生什麼。當然,如果該網站已關閉或clearTimeout被稱爲myVar

我無法驗證這個動作是否真的獨立發生,並且持續進行。

以下爲循環,是否有模擬進一步的代碼,看看myTimer函數是否會獨立執行。

我預計循環以i=0開始,然後等待三秒鐘,將日誌log 0添加到控制檯,然後繼續使用i=1等等。

取而代之的是,超時已開始,並且i已到達for循環的末尾,因此爲100

如何讓for循環等待迭代爲setTimeout

而且是setInterval真的每秒執行一次,獨立於以下代碼?例如。如果以下代碼具有需要一些處理/時間的操作,那麼在處理過程中時鐘是否會更新?

+0

你可能看看這裏:http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example –

+0

我會去,謝謝。如果我正確理解它,它會涉及迭代和'i'變量。你對'setInterval'和'setTimeout'的問題有評論嗎? – MikeDyson

+1

你也許會發現這個有用[JavaScript中有睡眠函數嗎?](http://stackoverflow.com/questions/1141302/is-there-a-sleep-function-in-javascript)。看起來你正在試圖使用settimeout暫停執行 - 但這樣做不起作用,因爲settimeout不會阻止執行,它通過將回調放到事件隊列中以便稍後執行 - 當前輪到的時間立即繼續。 –

回答

2

您可以使用因子i更改超時時間,並使用超過i的關閉來獲得正確的值。

function myTimer() { 
 
    var d = new Date(); 
 
    var t = d.toLocaleTimeString(); 
 
    document.getElementById("demo").innerHTML = t; 
 
} 
 

 
var i, 
 
    myVar = setInterval(myTimer, 1000); 
 

 
for (i = 0; i < 100; i++) { 
 
    setTimeout(function (i) { 
 
     return function() { 
 
      console.log("log " + i); 
 
     }; 
 
    }(i), 3000 * i); 
 
}
<p>A script on this page starts this clock:</p> 
 
<p id="demo"></p>

一個版本與超時後調用超時。

function myTimer() { 
 
    var d = new Date(); 
 
    var t = d.toLocaleTimeString(); 
 
    document.getElementById("demo").innerHTML = t; 
 
} 
 

 
function next() { 
 
    i++; 
 
    console.log("log " + i); 
 
    if (i < 300) { 
 
     setTimeout(next, 3000); 
 
    } 
 
} 
 

 
var i = 0, 
 
    myVar = setInterval(myTimer, 1000); 
 

 
setTimeout(next, 3000);
<p>A script on this page starts this clock:</p> 
 
<p id="demo"></p>

+1

這與我的意圖/預計我的代碼完全一樣,但我無法真正包裹我的頭如何工作。所以你在'setTimeout'中運行一個函數,它返回一個函數,它運行'console.log'?你爲每個'i'乘以3000ms的超時時間?對不起 - 我迷路了。 – MikeDyson

+0

沒錯。 'i'上的閉包保留了值並且與我的乘法延遲了返回函數的調用。 –

+0

這是否意味着for循環會立即運行所有100個'i's,並且每個日誌實際上都保持在*某處*保持,直到3秒*'i'已過期,然後執行? – MikeDyson

1

關於您setInterval問題,是的。它會每秒運行(不是毫秒級的嚴格)。假設您只需設置setInterval,然後運行需要半秒鐘才能運行的操作。間隔將會計數半秒,然後再運行半秒鐘。硬代碼不會延遲時鐘,如果您在間隔應該觸發的時刻正在運行代碼,它將等待代碼結束,因爲JavaScript是單線程的。這意味着如果在設置好你的間隔之後你運行的代碼持續時間超過1秒,間隔回調將會在它之後運行,所以它不會在1秒內被觸發。順便說一下,後續的間隔調用將在此間隔後被調用,但在間隔設置後。檢查這個小提琴(F12):https://jsfiddle.net/0gggmemu/4/

您會看到第一個間隔在代碼結束時調用,但後續間隔在間隔設置時稱爲計數(檢查毫秒,它們如何適合第一個日誌而不是開始一)。請注意,間隔不會堆疊。如果它應該調用10次間隔,它將只調用一次,然後等待下一次。如果時間精度對您很重要,那麼您應該在啓動時保存一個參考,並檢查每個區間的差異。

關於併發,同樣當你調用setInterval,當你調用setTimeout代碼將繼續執行,同時建立超時百作爲。如果你想讓代碼掛起,只需檢查我的小提琴。順便說一句,如果你的擔心是setTimeout鎖定setInterval,不要擔心,因爲代碼不會被阻止。如果你的代碼被卡住了某處,你只需半途而廢,但在回調驅動的應用程序中實現這一點很難。