本文是學習js定時器、單線程、同步異步任務的筆記,只適合初學者。
一、定時器(timer)
JavaScript提供定時執行代碼的功能,該功能主要由setTimeout()和setInterval()這兩個函數來實現
二、setTimeout()
1、使用規則
setTimeout函數用來指定某個函數或某段代碼,在多少毫秒之後執行。
第一個參數是函數名或者語句,第二個參數延遲的時間參數,單位爲ms
var timerId = setTimeout(function|code, delay)
setTimeout('console.log(2)',1000);
它返回定時器的編號,以後可以用來取消這個定時器。
2、使用注意
推遲執行的代碼必須以字符串的形式,放入setTimeout。
因爲引擎內部使用eval函數,將字符串轉爲代碼。
如果推遲執行的是函數,則可以直接將函數名,放入setTimeout。
一方面eval函數有安全顧慮,另一方面爲了便於JavaScript引擎優化代碼,setTimeout方法一般總是採用函數名的形式
三、setInterval()
setInterval函數的用法與setTimeout完全一致,區別僅僅在於setInterval指定某個任務每隔一段時間就執行一次。如果不取消的話,就會無限次的定時執行。
第一個參數是函數名或者語句,第二個參數是間隔執行的時間,單位爲ms
例一:實現自增數據輸出
var i=0
var timer=setInterval(function(){console.log(i++)},1000)
//不要在function傳遞i參數,不然得到的就是NaN
例二:實現定時器的功能
var timer=setInterval(function(){console.log(new Date)},1000)
四、解除定時器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)
}
執行結果:
解析:先執行主線程的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(事件循環)。
九、異步與回調函數
來源:如果沒有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()