js 定時器筆記

本文是學習js定時器、單線程、同步異步任務的筆記,只適合初學者。

一、定時器(timer)

JavaScript提供定時執行代碼的功能,該功能主要由setTimeout()和setInterval()這兩個函數來實現

二、setTimeout()

1、使用規則

setTimeout函數用來指定某個函數或某段代碼,在多少毫秒之後執行。
第一個參數是函數名或者語句,第二個參數延遲的時間參數,單位爲ms

var timerId = setTimeout(function|code, delay)
setTimeout('console.log(2)',1000);

它返回定時器的編號,以後可以用來取消這個定時器。

clipboard.png

2、使用注意

推遲執行的代碼必須以字符串的形式,放入setTimeout。
因爲引擎內部使用eval函數,將字符串轉爲代碼。
如果推遲執行的是函數,則可以直接將函數名,放入setTimeout
一方面eval函數有安全顧慮,另一方面爲了便於JavaScript引擎優化代碼,setTimeout方法一般總是採用函數名的形式

clipboard.png

三、setInterval()

setInterval函數的用法與setTimeout完全一致,區別僅僅在於setInterval指定某個任務每隔一段時間就執行一次。如果不取消的話,就會無限次的定時執行。
第一個參數是函數名或者語句,第二個參數是間隔執行的時間,單位爲ms
例一:實現自增數據輸出

var i=0
var timer=setInterval(function(){console.log(i++)},1000)
//不要在function傳遞i參數,不然得到的就是NaN

clipboard.png

例二:實現定時器的功能

var timer=setInterval(function(){console.log(new Date)},1000)

clipboard.png

四、解除定時器clearTimeout(),clearInterval()

setTimeout和setInterval函數,都返回一個表示計數器編號的整數值。
將該整數傳入clearTimeout和clearInterval函數,就可以取消對應的定時器。

var id1 = setTimeout(f,1000);
var id2 = setInterval(f,1000);

clearTimeout(id1);
clearInterval(id2);

五:舉個例子
其實這篇文章寫定時器的經典案例寫的很棒JavaScrip同步、異步、回調執行順序之經典閉包setTimeout分析

var i=0;
for(var i=0; i<10; i++){
  setTimeout(function(){
      console.log(i)
  }, 1000)
}

執行結果:

clipboard.png

解析:先執行主線程的for循環,for循環執行了10次,把匿名函數添加了到任務序列10次。等for循環執行完畢,i變成10之後,把任務序列的函數添加到主線程,輸出10次i=10.

var t = true;  
setTimeout(function(){ 
  t = false; 
}, 1000);  

while(t){console.log('end') }  

執行結果:不停的輸出end,不會再1000ms之後停止的。
解析:因爲while循環是在主線程執行,主線程的while的循環不停止,是不會再執行任務隊列裏面setimeout的函數的。

六、單線程模型

五、六、七章的內容全部來源於 阮一峯JavaScript 標準參考教程(alpha)
單線程模型指的是,JavaScript 只在一個線程上運行。也就是說,JavaScript 同時只能執行一個任務,其他任務都必須在後面排隊等待。

注意,JavaScript 只在一個線程上運行,不代表 JavaScript 引擎只有一個線程。事實上,JavaScript 引擎有多個線程,單個腳本只能在一個線程上運行(稱爲主線程),其他線程都是在後臺配合。

七、同步任務和異步任務

五、六、七章的內容全部來源於 阮一峯JavaScript 標準參考教程(alpha)
程序裏面所有的任務,可以分成兩類:同步任務(synchronous)和異步任務(asynchronous)。

同步任務是那些沒有被引擎掛起、在主線程上排隊執行的任務。只有前一個任務執行完畢,才能執行後一個任務。

異步任務是那些被引擎放在一邊,不進入主線程、而進入任務隊列的任務。只有引擎認爲某個異步任務可以執行了(比如 Ajax 操作從服務器得到了結果),該任務(採用回調函數的形式)纔會進入主線程執行。

八、任務隊列

JavaScript 運行時,除了一個正在運行的主線程,引擎還提供一個任務隊列(task queue),裏面是各種需要當前程序處理的異步任務。

首先,主線程會去執行所有的同步任務。等到同步任務全部執行完,就會去看任務隊列裏面的異步任務。如果滿足條件,那麼異步任務就重新進入主線程開始執行,這時它就變成同步任務了。等到執行完,下一個異步任務再進入主線程開始執行。一旦任務隊列清空,程序就結束執行。

引用這一次,徹底弄懂 JavaScript 執行機制這篇文章的解析:

同步和異步任務分別進入不同的執行"場所",同步的進入主線程,異步的進入Event Table並註冊函數。
當指定的事情完成時,Event Table會將這個函數移入Event Queue。
主線程內的任務執行完畢爲空,會去Event Queue讀取對應的函數,進入主線程執行。
上述過程會不斷重複,也就是常說的Event Loop(事件循環)。

clipboard.png

九、異步與回調函數

來源:如果沒有callback函數,會先執行f2,f3函數再執行f2函數。
但是如果f1,f2函數是有先後順序的,必須f1執行完成,再執行f2的話(f1可能是獲取ajax,f2是處理ajax數據),就需要回調函數。

給f1設置callback函數做參數,然後把這個參數當成函數執行,執行f1的過程中,設置了一個定時器,等數據到來之後,再去執行callback函數。然後把f2作爲f1的參數來調用

function f1(callback){
    setTimeout(function(){
        //做某件事,可能很久
        console.log('別急,開始執行f1')
        for(var i=0;i< 100000;i++){

        }
        console.log('f1執行完了')

        callback()
    }, 0);

}
function f2(){
    console.log('執行f2');
}
function f3(){
    console.log('執行f3');
}
f1(f2) //當f1執行完之後再執行 f2
f3()

10、函數節流

轉載一篇函數節流與函數防抖,寫的非常好,具體內容可看這篇文章。我不再贅述,我只記錄一下節流的代碼

 var timer
  function hiFrequency(){
      if(timer){
          clearTimeout(timer)
      }
        timer = setTimeout(function(){
             console.log('do something')
        }, 300)
  }

  hiFrequency()
  hiFrequency()
  hiFrequency()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章