//更新:這個問題沒參考意義,有點腦抽,已經申請關閉。具體可以看下面我的回答
前兩天看到一篇部落格提到:如果setInterval 回呼函數的執行時間大於規定的延遲時間,計時器被觸發時如果任務佇列有同一個定時器的回調函數,那麼這次的回調就會被忽略,意思是任務佇列中不會有兩個以上同一個定時器的回呼函數。語句表達不清,直接看程式碼:
(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 會清除。按照上面的說法來解釋這個結果:
100ms 時把第一個 for 迴圈放入任務佇列,空閒的主執行緒開始執行這個循環,耗時 863ms;
在第一個for 迴圈執行期間,第200ms 的時候第二次定時器被觸發,第二個for 迴圈被放入空的任務佇列,直到964ms之後主執行緒空閒開始執行第二個for 迴圈;
第三次到第八次定時器(理論上的序號)被觸發時,主執行緒在執行第一次for 循環,任務佇列中有第二個for 循環,所以這些函數被忽略,沒有進入任務隊列;
900ms 時,第九個定時器被觸發,主執行緒在執行第二個for 循環,任務佇列中不存在這個定時器的函數,所以這個定時器的函數被放入任務佇列,也就是結果中的「第3次定時器」;
1000ms 時,第十個定時器被觸發,由於第三條相同的原因被忽略,之後 setInterval 被清除。
不過另一個例子測試的結果卻不是這樣
for(var i=0;i<10000;i++){
console.log(1)
}
setInterval(function(){
console.log("定时器")
},1000)
瀏覽器先執行for 循環,我電腦上執行了13s 左右(電腦好差啊。。),按照上面的說法,在這13s 的時間內,任務隊列中只會存在一個這個定時器的函數,然後運行結果是在13s 之後同時列印13 個“定時器”,然後再以一秒為週期執行函數。
上面兩個例子是衝突的,setInterval 在這種情況下是怎麼進行工作的?希望能給個清晰的答案,最好帶有權威資料的。謝謝大噶。
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 執行緒解析之後的語句,計時器被註冊,然後正常執行。
所以兩個例子並沒有任何衝突的地方,第一個例子是對的,當主線程在執行定時器的函數,而且任務隊列有同一個定時器的函數時,在這期間這個定時器所有的觸發都會被忽略。