摘要:由于兩個都是異步函數(shù),按照執(zhí)行順序,先將放到,接著將移到,因為在指定要秒后才執(zhí)行,所以先于到注冊回調(diào)函數(shù)到,所以輸出的結(jié)果是。
眾所周知,Javascript是單線程語言, 這就意味著,所有的任務(wù)都必須按照順序執(zhí)行,只有等前面的一個任務(wù)執(zhí)行完畢了,下一個任務(wù)才能執(zhí)行。如果前面一個任務(wù)耗時很長,后一個任務(wù)就得一直等著,因此,為了實現(xiàn)主線程的不阻塞,就有了Event Loop。
1、javascript事件循環(huán)首先,我們先了解一下同步任務(wù)和異步任務(wù),同步任務(wù)指的是,在主線程上排隊執(zhí)行的任務(wù),只有前一個任務(wù)執(zhí)行完畢,才能執(zhí)行后一個任務(wù);異步任務(wù)指的是,不進入主線程、而進入"任務(wù)隊列"(task queue)的任務(wù),只有"任務(wù)隊列"通知主線程,某個異步任務(wù)可以執(zhí)行了,該任務(wù)才會進入主線程執(zhí)行。
為了更好的了解執(zhí)行機制,看下圖
以上圖說明主線程在執(zhí)行的時候產(chǎn)生堆(內(nèi)存分配)和堆棧(執(zhí)行上下文),JavaScript是單線程的,意味著當(dāng)執(zhí)行環(huán)境的堆棧中的一個任務(wù)(task)在執(zhí)行的時候,其它的任務(wù)都要處于等待狀態(tài)。當(dāng)主進程執(zhí)行到異步操作的時候就會將異步操作對應(yīng)的task放到event table,指定的事情完成時,Event Table會將這個函數(shù)移入Event Queue。主線程內(nèi)的任務(wù)執(zhí)行完畢為空,會去Event Queue讀取對應(yīng)的函數(shù),進入主線程執(zhí)行,因為這個過程是不斷重復(fù)的,所以稱為Event Loop(事件循環(huán)),接下來,我們用幾個例子進行分析
eg1:
console.log(1); setTimeout(function () { console.log(2); }) console.log(3); //執(zhí)行結(jié)果:1、3、2
我們來分析一下這段代碼,首先,根據(jù)執(zhí)行上下文可知,執(zhí)行環(huán)境棧中就有了一個task——console.log(1),輸出1。接著往下執(zhí)行,因為setTimeout是異步函數(shù),所以將setTimeout進入event table,注冊了一個回調(diào)函數(shù)在event queue,我們暫且稱為fun1,此時的流程如下圖:
接著往下執(zhí)行,執(zhí)行環(huán)境棧中會創(chuàng)建一個console.log(3)的task,并執(zhí)行它,輸出3,此時,執(zhí)行環(huán)境已經(jīng)沒有任務(wù)了,則去Event Queue讀取對應(yīng)的函數(shù),fun1被發(fā)現(xiàn),進入主線程輸出2,整個過程已經(jīng)完成,所以輸出的結(jié)果是1、3、2。
eg2:
setTimeout(function () { console.log(1) }, 3) setTimeout(function () { console.log(2) }) 輸出2,1
我們再來簡單的分析一下這個列子,我們暫且稱第一個setTimeout為Time1,第二個為Time2。由于兩個都是異步函數(shù),按照執(zhí)行順序,先將Time放到event Table,接著將Time移到event Table,因為Time在event Table指定要3秒后才執(zhí)行,所以Time2先于Time1到注冊回調(diào)函數(shù)到event queue,所以輸出的結(jié)果是2,1。
2、macro-task(宏任務(wù))、micro-task(微任務(wù))MacroTask: script(整體代碼), setTimeout, setInterval, setImmediate(node獨有), I/O, UI rendering MicroTask: process.nextTick(node獨有), Promises, Object.observe(廢棄), MutationObserver
任務(wù)又分為宏任務(wù)和微任務(wù)兩種,在同一個上下文中,總的執(zhí)行順序為“同步代碼—>microTask—>macroTask”,根據(jù)上面event loop的流程圖,我們用列子來做進一步的了解:
eg1:
setTimeout(function () { console.log(1); },0); console.log(2); process.nextTick(() => { console.log(3); }); new Promise(function (resolve, rejected) { console.log(4); resolve() }).then(res=>{ console.log(5); }) setImmediate(function () { console.log(6) }) console.log("end"); //輸出2、4、end、3、5、1、6
本例參考《JavaScript中的執(zhí)行機制》,里面有詳細的解釋,大家可以參考下。
3、優(yōu)先級我們將上面的例子稍微改一下,將process.nextTick移到promise的后面,看下面的代碼:
setTimeout(function () { console.log(1); },0); console.log(2); new Promise(function (resolve, rejected) { console.log(4); resolve() }).then(res=>{ console.log(5); }) process.nextTick(() => { console.log(3); }); setImmediate(function () { console.log(6) }) console.log("end");
按照前面的分析,先執(zhí)行同步代碼,先輸出“2,4,end”;然后是微任務(wù)promise輸出5,process.nextTick輸出3;最后的宏任務(wù)輸出1,6。所以結(jié)果為2,4,end,5,3,1,6,然后事實并非如此,結(jié)果還是輸出2、4、end、3、5、1、6,這是因為process.nextTick注冊的函數(shù)優(yōu)先級高于Promise**。
關(guān)于Event Loop的其他特殊情況,大家可參考文章一篇文章教會你Event loop——瀏覽器和Node和Event Loop的規(guī)范和實現(xiàn),里面有更詳細的介紹。
console.log(1) setTimeout(() => { console.log(2) new Promise(resolve => { console.log(4) resolve() }).then(() => { console.log(5) }) setTimeout(() => { console.log(999) }) }) new Promise(resolve => { console.log(7) resolve() }).then(() => { console.log(8) }) setTimeout(() => { console.log(9) new Promise(resolve => { console.log(11) resolve() }).then(() => { console.log(12) }) })
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/102381.html
摘要:主線程在任務(wù)隊列中讀取事件,這個過程是循環(huán)不斷地,所以這種運行機制叫做事件循環(huán)是在執(zhí)行棧同步代碼結(jié)束之后,下一次任務(wù)隊列執(zhí)行之前。 單線程 javascript為什么是單線程語言,原因在于如果是多線程,當(dāng)一個線程對DOM節(jié)點做添加內(nèi)容操作的時候,另一個線程要刪除這個DOM節(jié)點,這個時候,瀏覽器應(yīng)該怎么選擇,這就造成了混亂,為了解決這類問題,在一開始的時候,javascript就采用單線...
摘要:如果當(dāng)前沒有事件也沒有定時器事件,則返回。相關(guān)資料關(guān)于的架構(gòu)及設(shè)計思路的事件討論了使用線程池異步運行代碼。下一篇初窺事件機制的實現(xiàn)二中定時器的實現(xiàn) 在瀏覽器中,事件作為一個極為重要的機制,給予JavaScript響應(yīng)用戶操作與DOM變化的能力;在Node.js中,事件驅(qū)動模型則是其高并發(fā)能力的基礎(chǔ)。 學(xué)習(xí)JavaScript也需要了解它的運行平臺,為了更好的理解JavaScript的事...
摘要:瀏覽器與的異同,以及部分機制有人對部分迷惑,本身構(gòu)造函數(shù)是同步的,是異步。瀏覽器的的已全部分析完成,過程中引用阮一峰博客,知乎,部分文章內(nèi)容,侵刪。 瀏覽器與NodeJS的EventLoop異同,以及部分機制 PS:有人對promise部分迷惑,Promise本身構(gòu)造函數(shù)是同步的,.then是異步。---- 2018/7/6 22:35修改 javascript 是一門單線程的腳本...
摘要:前言前幾天在理解的事件環(huán)機制中引發(fā)了我對瀏覽器里的好奇。接下來理解瀏覽器中的,先看一張圖堆和棧堆是用戶主動請求而劃分出來的內(nèi)存區(qū)域,比如你,就是將一個對象存入堆中,可以理解為存對象。廢話不多說,直接上圖個人理解。參考資料運行機制詳解再談 前言 前幾天在理解node的事件環(huán)機制中引發(fā)了我對瀏覽器里Event Loop的好奇。我們都知道javascript是單線程的,任務(wù)是需要一個一個按順...
閱讀 2562·2021-09-02 15:40
閱讀 1566·2019-08-30 15:54
閱讀 1080·2019-08-30 12:48
閱讀 3398·2019-08-29 17:23
閱讀 1046·2019-08-28 18:04
閱讀 3664·2019-08-26 13:54
閱讀 606·2019-08-26 11:40
閱讀 2391·2019-08-26 10:15