一道涉及宏任務和微任務的題,以及同步和異步

微任務、宏任務與Event-Loop

setTimeout(function(){
		    console.log('1')
});
new Promise(function(resolve){
		console.log('2');
        resolve();
}).then(function(){
	 console.log('3')
});
 
console.log('4'); 

請你給出這段代碼的運行順序。

同步異步我看過很多的講解,大多都是要麼你就一個setTimeout函數,要麼就一個Promise函數。兩個函數放到一起的我還真沒見過。於是我就想:

settimeout肯定是異步的。 我也知道有一個event事件隊列,你setTimeout沒設置時間應該直接就進入這個隊列了吧,然後就是Promise的回掉函數進入event隊列。 答案應該是 2,4,1,3.

其實不然

首先說一下普通的異步函數的執行過程吧:
在這裏插入圖片描述

同步和異步任務分別進入不同的執行"場所",同步的進入主線程,異步的進入Event Table事件表並註冊函數。當指定的事情完成時,Event Table時間表會將這個函數移入事件隊列Event Queue。主線程內的任務執行完畢爲空,會去Event Queue事件隊列讀取對應的函數,進入主線程執行。上述過程會不斷重複,也就是常說的Event Loop(事件循環)。

但是js異步有一個機制,就是遇到宏任務,先執行宏任務,將宏任務放入事件隊列event queue,然後在執行微任務,將微任務放入事件隊列event queue

最騷的是,這兩個事件不放在同一個隊列 (這個queue不是一個queue)。當你往外拿的時候先從微任務事件隊列裏拿這個回調函數,然後再從宏任務的事件隊列queue上拿宏任務的回調函數。
再盜個圖

在這裏插入圖片描述

宏任務一般是:包括整體代碼script,setTimeout,setInterval。

微任務:Promise,process.nextTick。

記住就行了。然後回到開頭代碼。

因爲settimeout是宏任務,
雖然先執行的,但是他被放到了宏任務的event queue裏面,
然後代碼繼續往下檢查看有沒有微任務,檢測到Promise的then函數把他放入了微任務序列。

等到主線進程的所有代碼執行結束後。

先從微任務queue裏拿回調函數,然後微任務事件隊列queue空了後再從宏任務的事件隊列queue拿函數。

所以正確的執行結果當然是:2,4,3,1。

同步和異步的區別

同步,可以理解爲在執行完一個函數或方法之後,一直等待系統返回值或消息,這時程序是出於阻塞的,只有接收到返回的值或消息後才往下執行其他的命令。

異步,執行完函數或方法後,不必阻塞性地等待返回值或消息,只需要向系統委託一個異步過程,那麼當系統接收到返回值或消息時,系統會自動觸發委託的異步過程,從而完成一個完整的流程。

同步,就是實時處理(如打電話),比如服務器一接收客戶端請求,馬上響應,這樣客戶端可以在最短的時間內得到結果,但是如果多個客戶端,或者一個客戶端發出的請求很頻繁,服務器無法同步處理,就會造成湧塞。

同步如打電話,通信雙方不能斷(我們是同時進行,同步),你一句我一句,這樣的好處是,對方想表達的信息我馬上能收到,但是,我在打着電話,我無法做別的事情。

異步,就是分時處理(如收發短信),服務器接收到客戶端請求後並不是立即處理,而是等待服務器比較空閒的時候加以處理,可以避免湧塞。

異步如收發收短信,對比打電話,打電話我一定要在電話的旁邊聽着,保證雙方都在線,而收發短信,對方不用保證此刻我一定在手機旁,同時,我也不用時刻留意手機有沒有來短信。這樣的話,我看着視頻,然後來了短信,我就處理短信(也可以不處理),接着再看視頻。

對於寫程序,同步往往會阻塞,沒有數據過來,我就等着,異步則不會阻塞,沒數據來我幹別的事,有數據來去處理這些數據。

同步在一定程度上可以看做是單線程,這個線程請求一個方法後就待這個方法給他回覆,否則他不往下執行(死心眼)。

異步在一定程度上可以看做是多線程的(廢話,一個線程怎麼叫異步),請求一個方法後,就不管了,繼續執行其他的方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章