搜尋

首頁  >  問答  >  主體

javascript - 關於 setInterval 執行機制

//更新:這個問題沒參考意義,有點腦抽,已經申請關閉。具體可以看​​下面我的回答

前兩天看到一篇部落格提到:如果setInterval 回呼函數的執行時間大於規定的延遲時間,計時器被觸發時如果任務佇列有同一個定時器的回調函數,那麼這次的回調就會被忽略,意思是任務佇列中不會有兩個以上同一個定時器的回呼函數。語句表達不清,直接看程式碼:

例子1

(function(){
    var j=1;
    var start=new Date().getTime();
    var timr=setInterval(function(){
        console.log("第"+j+"次定时器开始时间:"+(new Date().getTime()-start));
        for(var i=0;i<5000;i++){console.log("")};
        console.log("第"+j+"次定时器结束时间:"+(new Date().getTime()-start));
        j++;
    },100);
    setTimeout(function(){
        clearInterval(timr)
    },1000)
})()

#setInterval 每隔 100ms 往任務佇列新增函數,在 1000ms 之後 setInterval 會清除。按照上面的說法來解釋這個結果:

  1. 100ms 時把第一個 for 迴圈放入任務佇列,空閒的主執行緒開始執行這個循環,耗時 863ms;

  2. 在第一個for 迴圈執行期間,第200ms 的時候第二次定時器被觸發,第二個for 迴圈被放入空的任務佇列,直到964ms之後主執行緒空閒開始執行第二個for 迴圈;

  3. 第三次到第八次定時器(理論上的序號)被觸發時,主執行緒在執行第一次for 循環,任務佇列中有第二個for 循環,所以這些函數被忽略,沒有進入任務隊列;

  4. 900ms 時,第九個定時器被觸發,主執行緒在執行第二個for 循環,任務佇列中不存在這個定時器的函數,所以這個定時器的函數被放入任務佇列,也就是結果中的「第3次定時器」;

  5. 1000ms 時,第十個定時器被觸發,由於第三條相同的原因被忽略,之後 setInterval 被清除。

例子2

不過另一個例子測試的結果卻不是這樣

for(var i=0;i<10000;i++){
    console.log(1)
}
setInterval(function(){
    console.log("定时器")
},1000)

瀏覽器先執行for 循環,我電腦上執行了13s 左右(電腦好差啊。。),按照上面的說法,在這13s 的時間內,任務隊列中只會存在一個這個定時器的函數,然後運行結果是在13s 之後同時列印13 個“定時器”,然後再以一秒為週期執行函數。

問題

上面兩個例子是衝突的,setInterval 在這種情況下是怎麼進行工作的?希望能給個清晰的答案,最好帶有權威資料的。謝謝大噶。

过去多啦不再A梦过去多啦不再A梦2749 天前659

全部回覆(2)我來回復

  • PHP中文网

    PHP中文网2017-05-19 10:37:06

    這個問題是我問的,現在發現有點腦抽。 。 。
    第二個例子中,for 迴圈執行過程中 js 執行緒一直被佔用,下面的語句還沒有被解析,也就是定時器還沒被註冊。把範例修改一下加上執行時間:

    var start=new Date().getTime();
    for(var i=0;i<10000;i++){
        console.log(1)
    }
    console.log("耗时"+(new Date().getTime()-start))
    setInterval(function(){
        console.log("定时器"+(new Date().getTime()-start))
    },1000)

    用這個例子來測試就很明白了。 上面的 for 迴圈執行了 1544ms 左右,這個時候 js 執行緒解析之後的語句,計時器被註冊,然後正常執行。

    所以兩個例子並沒有任何衝突的地方,第一個例子是對的,當主線程在執行定時器的函數,而且任務隊列有同一個定時器的函數時,在這期間這個定時器所有的觸發都會被忽略。

    回覆
    0
  • 巴扎黑

    巴扎黑2017-05-19 10:37:06

    但是,例 2 for 在結束前,setInterval 並沒有被執行啊

    回覆
    0
  • 取消回覆