天天看點

晝貓筆記 JavaScript -- 異步執行|定時器真的定時執行?

本篇主要内容:異步、定時器引發的思考

預計閱讀時間:8分鐘

了解

我們都知道在js中定時器有兩種

setInterval()

setTimeout()

setInterval()

:按照指定的周期(以毫秒計)來調用函數或計算表達式。方法會不停地調用函數,直到

clearInterval()

被調用或視窗被關閉。

setTimeout()

:在指定的毫秒數後調用函數或計算表達式。

那麼問題來了,定時器真的是定時執行的嗎? 剛開始我認為定時器肯定是定時執行的啊,要不然怎麼會叫做定時器呢,後來我感覺我好像錯了,是以今天就來說說這個問題 定時器真的是定時執行的嗎

測試

var start = Date.now()
console.log('啟動定時器前...')
setTimeout(function () {
   console.log('定時器執行了: ', Date.now()-start)
}, 100)
console.log('啟動定時器後...');
           
晝貓筆記 JavaScript -- 異步執行|定時器真的定時執行?

我們會發現定時器執行了101ms,一般會延遲一丁點(可以接受),說白了就是準确的,如果說300ms之後執行呢?再來看看下面的代碼

var start = Date.now()
console.log('啟動定時器前...')
setTimeout(function () {
   console.log('定時器執行了: ', Date.now()-start)
}, 100)
console.log('啟動定時器後...');
for (var i = 0; i < 1000000000; i++) {

}
           
晝貓筆記 JavaScript -- 異步執行|定時器真的定時執行?

如果像上邊這種情況,本來是200ms,但是現在變成了1941ms,那還合适嗎?

也就是說我們的定時器真的能保證定時嗎?

答案是不能,也可能延遲執行,是在原有設定的時間上又有延遲,加入本來是200ms, 那麼現在是1941ms,是以說定時器并不能真正保證定時執行

注意:定時器的回調函數是在主線程執行,無論是非回調函數還是回調函數都是在主線程執行

JS執行方式

這時候就說到了一個概念 — js是單線程執行的

那如何證明js執行是單線程的呢?尤其是一些回調函數中,我們把握不住是主線程執行還是分線程執行的,是以我們現在就驗證下js是單線程執行的

setTimeout(function () {
   console.log('timeout 2')
}, 2000)

setTimeout(function () {
   console.log('timeout 1')
}, 1000)
function fn () {
   console.log('fn()');
}
fn()
console.log('alert之前')
alert('提示...')
console.log('alert之後')
           
晝貓筆記 JavaScript -- 異步執行|定時器真的定時執行?
執行流程:fn() alert之前 彈窗

當我點選确認後,

timeout 2

timeout 1

是立即執行還是過一會執行?

晝貓筆記 JavaScript -- 異步執行|定時器真的定時執行?
執行流程 alert之後 timeout 1 timeout 2

我們發現是過一會執行,是以說

alert()

的作用是暫停目前主線程,同時暫停計時。 點選确認後,回複程式執行和計時

小結

如何證明js執行是單線程的?

setTimeout() 的回調函數是在主線程執行的

定時器回調函數隻有在運作棧中的代碼全部執行完後才有可能執行

setTimeout(function () {
   alert('2222222')
   console.log('timeout 2')
}, 2000)
setTimeout(function () {
   alert('1111111')
   console.log('timeout 1')
}, 1000)
function fn () {
   console.log('fn()');
}
fn()
console.log('alert之前')
alert('提示...')
console.log('alert之後')
           
晝貓筆記 JavaScript -- 異步執行|定時器真的定時執行?

其實呢到現在咱們也不能清楚地看到JS是如何執行的,要說到這個,我們就得說下代碼分類,之前也寫過代碼分類,全局代碼和函數局部代碼。

代碼分類

這一次呢我們分為初始化代碼和回調代碼

回調代碼就是回調函數中的代碼

晝貓筆記 JavaScript -- 異步執行|定時器真的定時執行?

setTimeout

是本文的初始代碼

接下來就是比較重要的一段函數了,這一段代碼中是誰先執行?

setTimeout(function () {
   console.log('timeout 0')
}, 0)
console.log('晝貓')
           
晝貓筆記 JavaScript -- 異步執行|定時器真的定時執行?

總結

JS引擎執行代碼的基本流程:

先執行初始化代碼:包含一些特别的代碼,例如:設定定時器、綁定事件監聽、發送ajax請求

在後面在某個時刻才會執行回調代碼

回調函數我們平常時候會說是異步執行

也就是說某些代碼(某些東西)必須在所有的初始化代碼執行後才有可能得到被執行,這樣的代碼我們成為異步代碼

今天的内容到這結束了,大家好好消化消化,認清JS的執行流程,清楚異步代碼執行流程

繼續閱讀