Event Loop

前言

Event Loop即事件循環(huán)飞主,是指瀏覽器或Node的一種解決javaScript單線程運(yùn)行時(shí)不會(huì)阻塞的一種機(jī)制座每,也就是我們經(jīng)常使用異步的原理前鹅。

為啥要弄懂Event Loop

是要增加自己技術(shù)的深度,也就是懂得JavaScript的運(yùn)行機(jī)制峭梳。

現(xiàn)在在前端領(lǐng)域各種技術(shù)層出不窮舰绘,掌握底層原理,可以讓自己以不變延赌,應(yīng)萬變除盏。

應(yīng)對(duì)各大互聯(lián)網(wǎng)公司的面試叉橱,懂其原理挫以,題目任其發(fā)揮。

堆窃祝,棧掐松、隊(duì)列

堆(Heap)

是一種數(shù)據(jù)結(jié)構(gòu),是利用完全二叉樹維護(hù)的一組數(shù)據(jù)粪小,分為兩種大磺,一種為最大,一種為最小堆探膊,將根節(jié)點(diǎn)最大叫做最大堆大根堆杠愧,根節(jié)點(diǎn)最小叫做最小堆小根堆

線性數(shù)據(jù)結(jié)構(gòu)逞壁,相當(dāng)于一維數(shù)組流济,有唯一后繼。

如最大堆

棧(Stack)(后進(jìn)先出)

在計(jì)算機(jī)科學(xué)中是限定僅在表尾進(jìn)行插入刪除操作的線性表腌闯。?是一種數(shù)據(jù)結(jié)構(gòu)绳瘟,它按照后進(jìn)先出的原則存儲(chǔ)數(shù)據(jù),先進(jìn)入的數(shù)據(jù)被壓入棧底姿骏,最后的數(shù)據(jù)棧頂糖声,需要讀數(shù)據(jù)的時(shí)候從棧頂開始彈出數(shù)據(jù)

是只能在某一端插入刪除特殊線性表

隊(duì)列(Queue)(先進(jìn)先出)

特殊之處在于它只允許在表的前端(front)進(jìn)行刪除操作蘸泻,而在表的后端(rear)進(jìn)行插入操作琉苇,和一樣,隊(duì)列是一種操作受限制的線性表悦施。

進(jìn)行插入操作的端稱為隊(duì)尾翁潘,進(jìn)行刪除操作的端稱為隊(duì)頭。? 隊(duì)列中沒有元素時(shí)歼争,稱為空隊(duì)列拜马。

隊(duì)列的數(shù)據(jù)元素又稱為隊(duì)列元素。在隊(duì)列中插入一個(gè)隊(duì)列元素稱為入隊(duì)沐绒,從隊(duì)列刪除一個(gè)隊(duì)列元素稱為出隊(duì)俩莽。因?yàn)殛?duì)列只允許在一端插入,在另一端刪除乔遮,所以只有最早進(jìn)入隊(duì)列的元素才能最先從隊(duì)列中刪除扮超,故隊(duì)列又稱為先進(jìn)先出(FIFO—first in first out)


Event Loop

在JavaScript中,任務(wù)被分為兩種蹋肮,一種宏任務(wù)(MacroTask)也叫Task出刷,一種叫微任務(wù)(MicroTask)。

MacroTask(宏任務(wù))

script全部代碼坯辩、setTimeout馁龟、setInterval、setImmediate(瀏覽器暫時(shí)不支持漆魔,只有IE10支持坷檩,具體可見MDN)、I/O改抡、UI Rendering矢炼。

MicroTask(微任務(wù))

Process.nextTick(Node獨(dú)有)、Promise阿纤、Object.observe(廢棄)句灌、MutationObserver(具體使用方式查看這里

瀏覽器中的Event Loop

Javascript?有一個(gè)?main thread?主線程和?call-stack?調(diào)用棧(執(zhí)行棧),所有的任務(wù)都會(huì)被放到調(diào)用棧等待主線程執(zhí)行欠拾。

JS調(diào)用棧

JS調(diào)用棧采用的是后進(jìn)先出的規(guī)則胰锌,當(dāng)函數(shù)執(zhí)行的時(shí)候,會(huì)被添加到棧的頂部清蚀,當(dāng)執(zhí)行棧執(zhí)行完成后匕荸,就會(huì)從棧頂移出,直到棧內(nèi)被清空枷邪。

同步任務(wù)和異步任務(wù)

Javascript單線程任務(wù)被分為同步任務(wù)異步任務(wù)榛搔,同步任務(wù)會(huì)在調(diào)用棧中按照順序等待主線程依次執(zhí)行诺凡,異步任務(wù)會(huì)在異步任務(wù)有了結(jié)果后,將注冊(cè)的回調(diào)函數(shù)放入任務(wù)隊(duì)列中等待主線程空閑的時(shí)候(調(diào)用棧被清空)践惑,被讀取到棧內(nèi)等待主線程的執(zhí)行腹泌。

任務(wù)隊(duì)列Task Queue,即隊(duì)列尔觉,是一種先進(jìn)先出的一種數(shù)據(jù)結(jié)構(gòu)凉袱。

事件循環(huán)的進(jìn)程模型

選擇當(dāng)前要執(zhí)行的任務(wù)隊(duì)列,選擇任務(wù)隊(duì)列中最先進(jìn)入的任務(wù)侦铜,如果任務(wù)隊(duì)列為空即null专甩,則執(zhí)行跳轉(zhuǎn)到微任務(wù)(MicroTask)的執(zhí)行步驟。

將事件循環(huán)中的任務(wù)設(shè)置為已選擇任務(wù)钉稍。

執(zhí)行任務(wù)涤躲。

將事件循環(huán)中當(dāng)前運(yùn)行任務(wù)設(shè)置為null。

將已經(jīng)運(yùn)行完成的任務(wù)從任務(wù)隊(duì)列中刪除贡未。

microtasks步驟:進(jìn)入microtask檢查點(diǎn)种樱。

更新界面渲染。

返回第一步俊卤。

執(zhí)行進(jìn)入microtask檢查點(diǎn)時(shí)嫩挤,用戶代理會(huì)執(zhí)行以下步驟:

設(shè)置microtask檢查點(diǎn)標(biāo)志為true。

當(dāng)事件循環(huán)microtask執(zhí)行不為空時(shí):選擇一個(gè)最先進(jìn)入的microtask隊(duì)列的microtask消恍,將事件循環(huán)的microtask設(shè)置為已選擇的microtask岂昭,運(yùn)行microtask,將已經(jīng)執(zhí)行完成的microtask為null哺哼,移出microtask中的microtask佩抹。

清理IndexDB事務(wù)

設(shè)置進(jìn)入microtask檢查點(diǎn)的標(biāo)志為false。

執(zhí)行棧在執(zhí)行完同步任務(wù)后取董,查看執(zhí)行棧是否為空,如果執(zhí)行棧為空无宿,就會(huì)去檢查微任務(wù)(microTask)隊(duì)列是否為空茵汰,如果為空的話,就執(zhí)行Task(宏任務(wù))孽鸡,否則就一次性執(zhí)行完所有微任務(wù)蹂午。

每次單個(gè)宏任務(wù)執(zhí)行完畢后,檢查微任務(wù)(microTask)隊(duì)列是否為空彬碱,如果不為空的話豆胸,會(huì)按照先入先出的規(guī)則全部執(zhí)行完微任務(wù)(microTask)后,設(shè)置微任務(wù)(microTask)隊(duì)列為null巷疼,然后再執(zhí)行宏任務(wù)晚胡,如此循環(huán)。

舉個(gè)例子

console.log('script start');

setTimeout(function() {

? console.log('setTimeout');

}, 0);

Promise.resolve().then(function() {

? console.log('promise1');

}).then(function() {

? console.log('promise2');

});

console.log('script end');

首先我們劃分幾個(gè)分類:

第一次執(zhí)行:

Tasks:run script、 setTimeout callback

Microtasks:Promise then

JS stack: script

Log: script start估盘、script end瓷患。

執(zhí)行同步代碼,將宏任務(wù)(Tasks)和微任務(wù)(Microtasks)劃分到各自隊(duì)列中遣妥。

第二次執(zhí)行:

Tasks:run script擅编、 setTimeout callback

Microtasks:Promise2 then

JS stack: Promise2 callback

Log: script start、script end箫踩、promise1爱态、promise2

執(zhí)行同步代碼后,檢測(cè)到微任務(wù)(Microtasks)隊(duì)列中不為空境钟,執(zhí)行Promise1肢藐,執(zhí)行完成Promise1后,調(diào)用Promise2.then吱韭,放入微任務(wù)(Microtasks)隊(duì)列中吆豹,再執(zhí)行Promise2.then。

第三次執(zhí)行:

Tasks:setTimeout callback

Microtasks:

JS stack:

Log: script start理盆、script end痘煤、promise1、promise2猿规、setTimeout

當(dāng)微任務(wù)(Microtasks)隊(duì)列中為空時(shí)衷快,執(zhí)行宏任務(wù)(Tasks),執(zhí)行setTimeout callback姨俩,打印日志蘸拔。

第四次執(zhí)行:

Tasks:setTimeout callback

Microtasks:

JS stack:

Log: script start、script end环葵、promise1调窍、promise2、setTimeout

清空Tasks隊(duì)列和JS stack张遭。

以上執(zhí)行幀動(dòng)畫可以查看Tasks, microtasks, queues and schedules

具體查看

再舉個(gè)例子

console.log('script start')

async function async1() {

? await async2()

? console.log('async1 end')

}

async function async2() {

? console.log('async2 end')

}

async1()

setTimeout(function() {

? console.log('setTimeout')

}, 0)

new Promise(resolve => {

? console.log('Promise')

? resolve()

})

? .then(function() {

? ? console.log('promise1')

? })

? .then(function() {

? ? console.log('promise2')

? })

console.log('script end')

這里需要先理解async/await邓萨。

async/await在底層轉(zhuǎn)換成了promise和then回調(diào)函數(shù)。

也就是說菊卷,這是promise的語法糖缔恳。

每次我們使用await, 解釋器都創(chuàng)建一個(gè)promise對(duì)象,然后把剩下的async函數(shù)中的操作放到then回調(diào)函數(shù)中洁闰。

async/await的實(shí)現(xiàn)歉甚,離不開Promise。從字面意思來理解扑眉,async是“異步”的簡(jiǎn)寫纸泄,而await是async wait的簡(jiǎn)寫可以認(rèn)為是等待異步方法執(zhí)行完成赖钞。


參考

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市刃滓,隨后出現(xiàn)的幾起案子仁烹,更是在濱河造成了極大的恐慌,老刑警劉巖咧虎,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件卓缰,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡砰诵,警方通過查閱死者的電腦和手機(jī)征唬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來茁彭,“玉大人总寒,你說我怎么就攤上這事±矸危” “怎么了摄闸?”我有些...
    開封第一講書人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)妹萨。 經(jīng)常有香客問我年枕,道長(zhǎng),這世上最難降的妖魔是什么乎完? 我笑而不...
    開封第一講書人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任熏兄,我火速辦了婚禮,結(jié)果婚禮上树姨,老公的妹妹穿的比我還像新娘摩桶。我一直安慰自己,他們只是感情好帽揪,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開白布硝清。 她就那樣靜靜地躺著,像睡著了一般台丛。 火紅的嫁衣襯著肌膚如雪耍缴。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,590評(píng)論 1 305
  • 那天挽霉,我揣著相機(jī)與錄音,去河邊找鬼变汪。 笑死侠坎,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的裙盾。 我是一名探鬼主播实胸,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼他嫡,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了庐完?” 一聲冷哼從身側(cè)響起钢属,我...
    開封第一講書人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎门躯,沒想到半個(gè)月后淆党,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡讶凉,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年染乌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片懂讯。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡荷憋,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出褐望,到底是詐尸還是另有隱情勒庄,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布瘫里,位于F島的核電站实蔽,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏减宣。R本人自食惡果不足惜盐须,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望漆腌。 院中可真熱鬧贼邓,春花似錦、人聲如沸闷尿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽填具。三九已至统舀,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間劳景,已是汗流浹背誉简。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留盟广,地道東北人闷串。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像筋量,于是被迫代替她去往敵國(guó)和親烹吵。 傳聞我的和親對(duì)象是個(gè)殘疾皇子碉熄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容