摘要:而事件循環(huán)機制主要以來調(diào)用棧來處理執(zhí)行順序,依靠任務(wù)隊列來執(zhí)行代碼的執(zhí)行。當(dāng)微任務(wù)執(zhí)行完畢之后,第一輪循環(huán)結(jié)束,進入第二輪循環(huán),繼續(xù)執(zhí)行宏任務(wù),此時執(zhí)行,進入函數(shù)調(diào)用棧,輸出。
? ? ??事件循環(huán)機制控制了javascript代碼的執(zhí)行順序。我們都知道javascript是單線程,這個線程中擁有唯一的一個事件循環(huán)。(新標(biāo)準(zhǔn)web workker有多線程的概念。)而事件循環(huán)機制主要以來調(diào)用棧來處理執(zhí)行順序,依靠任務(wù)隊列來執(zhí)行代碼的執(zhí)行。隊列的概念可以參考https://segmentfault.com/a/11...
? ? ? 在一個線程中,調(diào)用棧是唯一的,但是任務(wù)隊列可以是多個,并且分為macro-task(宏任務(wù))及micro-task(微任務(wù))兩種類型。
? ? ? 這里需要區(qū)分一個概念任務(wù)及任務(wù)源。setTimeout及Promise是任務(wù)源。他們指定具體的執(zhí)行任務(wù)進入任務(wù)隊列。只有回調(diào)中的函數(shù)才會進入任務(wù)隊列。就像setTimeout它其實是麗姬執(zhí)行的,只是它的回調(diào)函數(shù)才會延遲執(zhí)行。promise也是,本身是立即執(zhí)行的,但是then才會在“未來”執(zhí)行。
? ? ? javascript的執(zhí)行順序是從整體代碼開始做循環(huán),之后全局上下文進入函數(shù)調(diào)用棧。直到調(diào)用棧清空。整體代碼所處的macro-task執(zhí)行完成,輪到micro-task任務(wù)執(zhí)行。一直循環(huán)直到所有的任務(wù)執(zhí)行完成。
? ? ? 當(dāng)然,不同的任務(wù)源的任務(wù)會進入不同的任務(wù)隊列。
? ? ? 具體的可以參考一下代碼。
? ? ? 1.事件循環(huán)從macro-task開始,整體代碼開始執(zhí)行。整體代碼script進入macro-task,并且執(zhí)行代碼main進入調(diào)用函數(shù)調(diào)用棧。遇到第12行的打印輸出start
? ? ? 2.繼續(xù)執(zhí)行,遇到13行的setTimeout,它是宏任務(wù)源。便將其分發(fā)到對應(yīng)的隊列中。接著遇到16行的promise。promise.resolve會進入函數(shù)調(diào)用棧直接執(zhí)行,因此打印promise1,接著將p.then1和p.then分發(fā)到對應(yīng)的微任務(wù)隊列中。繼續(xù)執(zhí)行代碼,遇到第24行的打印便輸出end。大致圖示如下圖。
? ? ? 3.script執(zhí)行完畢,即第一個宏任務(wù)執(zhí)行完畢,開始執(zhí)行微任務(wù)。現(xiàn)在微任務(wù)只有一個隊列,里面有p1.then1,p1.then2。隊列是先進先出,因此先執(zhí)行p1.then1,p1.then1進入函數(shù)調(diào)用棧,輸出then1。
? ? ? 4. p1.then1執(zhí)行完畢之后,出棧。但是此時的正在進行的微任務(wù)還未執(zhí)行完完畢,會繼續(xù)執(zhí)行p1.then2,p1.then2進入函數(shù)調(diào)用棧,輸出then2。此時,微任務(wù)正在進行的隊列已經(jīng)執(zhí)行完畢。
? ? ? 5.當(dāng)微任務(wù)執(zhí)行完畢之后,第一輪循環(huán)結(jié)束,進入第二輪循環(huán),繼續(xù)執(zhí)行宏任務(wù),此時setTimeout執(zhí)行,進入函數(shù)調(diào)用棧,輸出setTimeout1。
? ? ? 6.此時,宏任務(wù)隊列和微任務(wù)隊列中都沒有任務(wù)了。代碼執(zhí)行完畢,就不會有任何輸出了。
? ? ? 我們上述的代碼只涉及到一個宏任務(wù)及微任務(wù)隊列的情況。但如果情況更加復(fù)雜會有什么樣的表現(xiàn)呢?大家可以看看下面的代碼。根據(jù)上面的原理試著自己分析下結(jié)果~
? ? ? 1.還是跟以前的例子一樣,事件循環(huán)從macro-task開始,整體代碼開始執(zhí)行。輸出start。setTimeout1,setTimeout2依次進入新的宏任務(wù)隊列。p3.resolve執(zhí)行,輸出promise31,promise31。并將setTimeout3放入新的宏任務(wù)隊列。因為setTimeout3不是整體代碼中定義的,而是在promise中定義的,需要重新開啟一個宏任務(wù)隊列。然后p3.then1,p3.then2分別進入微任務(wù)隊列。p3.resolve出棧后,整體代碼繼續(xù)執(zhí)行,這里就不重新畫圖了,輸出end。
? ? ? 2.整體代碼已執(zhí)行完成,循環(huán)進入微任務(wù)。此時p3.then1進入函數(shù)調(diào)用棧。輸出then31。遇到新的定時,將set4放入宏任務(wù)隊列。遇到新的promise,繼續(xù)將p4.resolve入棧。輸出promise41,promise42。遇到新的定時,將set5放入宏任務(wù)隊列。此時需要注意的是,在微任務(wù)中繼續(xù)有promise。此時的promise.then不再進入微任務(wù)隊列,而是直接執(zhí)行。因此輸出then41。
? ? ? 3.微任務(wù)隊列還未執(zhí)行完畢,繼續(xù)執(zhí)行p3.then2。直接輸出then32。此時微任務(wù)隊列已經(jīng)執(zhí)行完畢,進入下一輪循環(huán)。
? ? ? 4.新的循環(huán)開始。隊列是先進先出,因此在宏任務(wù)當(dāng)前隊列中,set1先執(zhí)行,進入函數(shù)調(diào)用棧。輸出setTimeout1。遇到新的promise,繼續(xù)將p1.resolve入棧。輸出promise1。還是跟上看一樣,在宏任務(wù)中繼續(xù)有promise。此時的promise.then不再進入微任務(wù)隊列,而是直接執(zhí)行。直接輸出then1。
? ? ? 5.setTimeout1執(zhí)行完畢,正在執(zhí)行的宏任務(wù)隊列還有任務(wù),繼續(xù)執(zhí)行setTimeout2。setTimeout2進入函數(shù)調(diào)用棧。跟setTimeout1的分析一樣,陸續(xù)輸出setTimeout2,promise2,then2。
? ? ? 6.當(dāng)前宏任務(wù)執(zhí)行完畢,微任務(wù)內(nèi)沒有可執(zhí)行的隊列。繼續(xù)下一輪循環(huán)。執(zhí)行set3。輸出setTimeout3。遇到新的promsie,還是跟上面的分析一樣,輸出promise5,then5。因為微任務(wù)一直沒有可執(zhí)行的隊列。宏任務(wù)內(nèi)的隊列依次執(zhí)行,輸出setTimeout4,setTimeout5。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/104733.html
摘要:主線程不斷重復(fù)上面的三步,此過程也就是常說的事件循環(huán)。所以主線程代碼執(zhí)行時間過長,會阻塞事件循環(huán)的執(zhí)行。參考資料這一次,徹底弄懂執(zhí)行機制任務(wù)隊列的順序機制事件循環(huán)搞懂異步事件輪詢與中的事件循環(huán) 1. 說明 讀過本文章后,您能知道: JavaScript代碼在瀏覽器中的執(zhí)行機制和事件循環(huán) 面試中經(jīng)常遇到的代碼輸出順序問題 首先通過一段代碼來驗證你是否了解代碼輸出順序,如果你不知道輸出...
摘要:了解事件循環(huán)機制有助于理解的執(zhí)行過程,同時這也是面試常見題。那么這個回調(diào)函數(shù)將在何時由誰執(zhí)行呢已知是瀏覽器環(huán)境提供的,因此瀏覽器將對它進行處理,瀏覽器會在本次事件完成,即計時結(jié)束后,將回調(diào)函數(shù)加入循環(huán)隊列中,然后等待被加入執(zhí)行棧執(zhí)行。 如果有人問JavaScript是什么,也許你會說它是一個單線程、非阻塞、異步、解釋型的腳本語言。那么作為一個單線程語言,它是怎么實現(xiàn)非阻塞、異步的?這就...
摘要:如果沒有其他異步任務(wù)要處理比如到期的定時器,會一直停留在這個階段,等待請求返回結(jié)果。執(zhí)行的執(zhí)行事件關(guān)閉請求的,例如事件循環(huán)的每一次循環(huán)都需要依次經(jīng)過上述的階段。因此,才會早于執(zhí)行。 showImg(https://segmentfault.com/img/bVbnY76); 概念 同步任務(wù)(Synchronous) 在主線程上排隊執(zhí)行的任務(wù),只有前一個任務(wù)執(zhí)行完畢,才能執(zhí)行后一個任務(wù) ...
摘要:主線程要明確的一點是,主線程跟執(zhí)行棧是不同概念,主線程規(guī)定現(xiàn)在執(zhí)行執(zhí)行棧中的哪個事件。主線程循環(huán)即主線程會不停的從執(zhí)行棧中讀取事件,會執(zhí)行完所有棧中的同步代碼。以上參考資料詳解中的事件循環(huán)機制中的事件循環(huán)運行機制詳解再談 showImg(https://segmentfault.com/img/remote/1460000015317437?w=1920&h=1080); 前言 大家都...
摘要:前端基礎(chǔ)進階正是圍繞這條線索慢慢展開,而事件循環(huán)機制,則是這條線索的最關(guān)鍵的知識點。特別是中正式加入了對象之后,對于新標(biāo)準(zhǔn)中事件循環(huán)機制的理解就變得更加重要。之后全局上下文進入函數(shù)調(diào)用棧。 showImg(https://segmentfault.com/img/remote/1460000008811705); JavaScript的學(xué)習(xí)零散而龐雜,因此很多時候我們學(xué)到了一些東西,但...
閱讀 1010·2023-04-25 19:35
閱讀 2672·2021-11-22 09:34
閱讀 3702·2021-10-09 09:44
閱讀 1729·2021-09-22 15:25
閱讀 2944·2019-08-29 14:00
閱讀 3377·2019-08-29 11:01
閱讀 2605·2019-08-26 13:26
閱讀 1741·2019-08-23 18:08