剛開始學(xué)習(xí) JavaScript 的時候硼讽,生搬硬套的知道了定時器是 JavaScript 中最基礎(chǔ)的異步操作曙聂,由于 JavaScript 是單線程腿箩,如果中間某個任務(wù)耗時過長律杠,后面的必須要等待块差,比如我們?yōu)g覽網(wǎng)頁的時候圖片會因為網(wǎng)絡(luò)原因加載的很慢,為了讓我們有更好的用戶體驗燎潮,我們可以把頁面骨架先渲染出來喻鳄,一些耗費資源的東西我們就通過異步來加載,可以通過一個圖示來感受一下:
同步和異步任務(wù)分別進入不同的執(zhí)行"場所"确封,同步的進入主線程除呵,異步的進入Event Table并注冊函數(shù);
當(dāng)指定的事情完成時,Event Table會將這個函數(shù)移入Event Queue;
主線程內(nèi)的任務(wù)執(zhí)行完畢為空爪喘,會去Event Queue讀取對應(yīng)的函數(shù)颜曾,進入主線程執(zhí)行;
上述過程會不斷重復(fù),也就是常說的Event Loop(事件循環(huán));
最開始接觸到異步相關(guān)的是 setTimeout 和 setInterval秉剑,對于一些輪詢的操作很方便泛豪,隨著接觸的深入,了解到事件隊列的概念,原來引擎還分為 JavaScript 引擎和定時器引擎诡曙,二者的執(zhí)行時機也是有先后的臀叙,即便 delay 設(shè)置為0,也是必須得主線程執(zhí)行完后不用等待可以馬上執(zhí)行价卤,而不是高于主線程的優(yōu)先級劝萤,結(jié)合代碼看一下:
setTimeout(function() {
console.log('setTimeout')
}, 0)
console.log('我先執(zhí)行')
// 我先執(zhí)行
// setTimeout
從上述代碼中我們有個直觀的體會,就是定時器任務(wù)優(yōu)先級低于主線程任務(wù)荠雕,另外我們從 MDN 上看到定時器可以傳入多個參數(shù)稳其,分別是
var timeoutID = scope.setTimeout(function[, delay, param1, param2, ...])
這里傳入 function 和 delay 都是很常見的, delay 后面的參數(shù)是可選的炸卑,一旦定時器到期既鞠,它們會作為參數(shù)傳遞給 function;另外這里對于定時器的 id 需要了解一下盖文,timeoutID 是一個定時器的 id嘱蛋,這個值可以傳遞給 clearTimeout 來取消該定時器,并且 setTimeout 和 setInterval 共用一個編號池五续,所以你在代碼中調(diào)用 clearTimeout() 和 clearInterval() 效果相同洒敏,但是不建議混用。
setTimeout(function(a, b) {
console.log(a+b)
}, 1000, 1, 2)
使用定時器輪詢接口
結(jié)合實際的業(yè)務(wù)場景來說吧疙驾,當(dāng)我們需要對于某個接口做輪詢的時候凶伙,自然就想到了定時器,最開始對于定時器的理解是 setTimeout 執(zhí)行一次就結(jié)束了它碎,setInterval 可以重復(fù)執(zhí)行函荣,所以輪詢的時候理所當(dāng)然的選擇了 setInterval,剛開始效果杠杠滴扳肛,可是過了一段時間如果網(wǎng)絡(luò)波動就會導(dǎo)致定時器不是那么 '準(zhǔn)時' 傻挂,當(dāng)時很奇怪,后面查找資料發(fā)現(xiàn)這是 setInterval 的一個弊端挖息,它指定的時間是每次執(zhí)行的間隔金拒,并不包含當(dāng)前請求消耗的時間,所以當(dāng)某次請求時間大于指定時間套腹,這個定時器就開始 '不準(zhǔn)'了绪抛,為了保證兩次執(zhí)行有固定的 delay,通過 setTimeout 來達(dá)到想要的效果电禀,看下代碼:
function interval(func, wait){
var interv = function(){
func.call(null)
setTimeout(interv, wait)
}
setTimeout(interv, wait)
}
interval(function() {
console.log(123)
// 執(zhí)行相關(guān)操作
}, 1000)
通過上面的方式我們可以平滑的實現(xiàn)接口輪詢睦疫,以及類似的業(yè)務(wù),比如輪播圖等鞭呕。
還有就是了解一下 setTimeout 會出現(xiàn) this 指向全局的問題,不過現(xiàn)在使用箭頭函數(shù)就可以很方便避免這種問題了,不然你還得手動將 this 綁定回來葫松,比較麻煩