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