大家好,我是IT修真院武漢第10期學員,一枚正直、純潔、善良的前端程序員。
今天給大家分享一下,修真院官網任務JS-task1,深度思考的知識點——什么是定時器?有什么用?
1.背景介紹
瀏覽器(或者說JS引擎)執行JS的機制是基于事件循環。
由于JS是單線程,所以同一時間只能執行一個任務,其他任務就得排隊,后續任務必須等到前一個任務結束才能開始執行。
為了避免因為某些長時間任務造成的無意義等待,JS引入了異步的概念,用另一個線程來管理異步任務。
同步任務直接在主線程隊列中順序執行,而異步任務會進入另一個任務隊列,不會阻塞主線程。等到主線程隊列空了(執行完了)的時候,就會去異步隊列查詢是否有可執行的異步任務了(異步任務通常進入異步隊列之后還要等一些條件才能執行,如ajax請求、文件讀寫),如果某個異步任務可以執行了便加入主線程隊列,以此循環。
JS定時器
JS的定時器目前有三個:setTimeout、setInterval和setImmediate。
定時器也是一種異步任務,通常瀏覽器都有一個獨立的定時器模塊,定時器的延遲時間就由定時器模塊來管理,當某個定時器到了可執行狀態,就會被加入主線程隊列。
JS定時器非常實用,做動畫的肯定都用到過,也是最常用的異步模型之一。
有時候一些奇奇怪怪的問題,加一個setTimeout(fn, 0)(以下簡寫setTimeout(0))就解決了。不過,如果對定時器本身不熟悉,也會產生一些奇奇怪怪的問題。
2.知識剖析
setTimeout
setTimeout(fn, x)表示延遲x毫秒之后執行fn。
使用的時候千萬不要太相信預期,延遲的時間嚴格來說總是大于x毫秒的,至于大多少就要看當時JS的執行情況了。另外,多個定時器如不及時清除(clearTimeout),會存在干擾,使延遲時間更加捉摸不透。所以,不管定時器有沒有執行完,及時清除已經不需要的定時器是個好習慣。HTML5規范規定最小延遲時間不能小于4ms,即x如果小于4,會被當做4來處理。 不過不同瀏覽器的實現不一樣,比如,Chrome可以設置1ms,IE11/Edge是4ms。setTimeout注冊的函數fn會交給瀏覽器的定時器模塊來管理,延遲時間到了就將fn加入主進程執行隊列,如果隊列前面還有沒有執行完的代碼,則又需要花一點時間等待才能執行到fn,所以實際的延遲時間會比設置的長。如在fn之前正好有一個超級大循環,那延遲時間就不是一丁點了。
setInterval
setInterval的實現機制跟setTimeout類似,只不過setInterval是重復執行的。 對setInterval(fn, 100)容易產生一個誤區:并不是上一次fn執行完了之后再過100ms才開始執行下一次fn。 事實上,setInterval并不管上一次fn的執行結果,而是每隔100ms就將fn放入主線程隊列,而兩次fn之間具體間隔多久就不一定了,跟setTimeout實際延遲時間類似,和JS執行情況有關。
3.常見問題
定時器引起的代碼超級無敵托馬斯回旋式爆炸阻塞
4.解決方案
清除定時器唄~
5.編碼實戰
還有那些方法可以實現定時器或類似定時器的效果?
Promise
Promise是很常用的一種異步模型,如果我們想讓代碼在下一個事件循環執行,可以選擇使用setTimeout(0)、setImmediate、requestAnimationFrame(Chrome)和Promise。而且Promise的延遲比setImmediate更低,意味著Promise比setImmediate先執行。
6.擴展思考
7.參考文獻
8.更多討論
詳情請看:
Q1:在我們日常工作中,有哪些地方會用到定時器?
答:動畫。
Q2:除了前文提到的兩種常用的定時器,你還接觸過哪些定時器的使用?
答:promise。
Q3:在定時器的使用過程中可能存在哪些問題?
答:代碼阻塞。