setTimeout與setInterval執行
首先我們看一下以下代碼打印結果
console.log(1);setTimeout(function() { console.log(2); },100)setTimeout(function() { console.log(3); },50)console.log(4);打印結果是 1、4、3、2,你可能覺得理所應當,那我們再看下下面這個例子
console.log(1);setTimeout(function() { console.log(2); },0)console.log(3);這次的結果又會是什么呢?
1、3、2,不是1、2、3。到這里你可能會有疑惑了,明明定時器設置的時間為0,而且瀏覽器解析js是按照從上到下執行的,應該是1、2、3才對啊?
到這里我們要提一下瀏覽器的線程問題。
與js相關的瀏覽器線程有三個(注意:js解析是單線程) - js代碼執行線程( 主線程 ) - UI渲染線程 - 事件循環線程
其中js代碼執行線程與UI渲染線程兩者是互斥的,也就是說js代碼執行線程運行的時候,UI渲染線程會停止工作,這樣做也是為了防止js中的DOM操作會導致兩線程沖突;而事件循環線程比較特殊,接下來會根據setTimerout的執行過程進行講解其作用。
回到上面的第一道題目
console.log(1); setTimeout(function() { console.log(2); },100) setTimeout(function() { console.log(3); },50) console.log(4);執行過程:
js主線程運行,遇到console.log(1),直接運行,在控制臺輸出結果;
主線程繼續運行,然后遇到第一個setTimeout,接著setTimeout中的回調函數會被放入到一個事件隊列中(這里的事件隊里可以想象成一個備忘錄,里面記錄的全是一些需要做而未做的事);
遇到第二個setTimeout,其中的回調函數依然被加入到事件隊列中;
執行console.log(4),到這里主線程的任務全部執行完畢,除了setTimeout里面的回調函數;
這個時候,我們還未說明的事件循環線程開始工作,它會去循環遍歷事件隊列(也就是我們的備忘錄),如果事件隊列中有回調函數,它就會將事件隊列中的回調函數重新交給主線程;
主線程收到回調函數,然后開始執行函數體。(這里要注意,因為兩個setTimeout本身有執行時間,所以在這里的時候就會根據時間的長短按順序執行啦。)
setInterval原理與之相同,不作另說。
總的來說,setTimeout與setInterval的執行會等到主線程的所有任務全部執行后,才會再執行其中的回調函數,所以在使用它們的時候也要注意,特別是在主線程中有特別耗時的任務的時候,兩種定時器會被不可預測的延后。
講到這里,大家有沒有想到什么呢?
恩,就是異步,setTimeout的執行有沒有一點異步的感覺呢?但又因為它必須是等到主線程全部執行完才會執行,所以可以稱之為偽異步。
新聞熱點
疑難解答
圖片精選