Event loop

瀏覽器中的 Event loop

event loop

JavaScript 是單線程的

? ?????首先,語言產(chǎn)生的時代多進程多線程的架構(gòu)并不普及誓禁,基于當時硬件支持也不好鲜屏,而且 多線程比較復(fù)雜俺陋,多線程操作需要加鎖,使得編碼方面就會變得很復(fù)雜考廉;而且當時 JavaScript?只是處理頁面的用戶交互秘豹,以及操作 DOM 和 CSS,如果是多線程昌粤,兩個線程 同時操作 同一個 DOM既绕, 就會產(chǎn)生 預(yù)期的結(jié)果,所以 JavaScript?選擇單線程婚苹。

基本概念

? ? JavaScript 分為 同步任務(wù) 異步任務(wù)岸更;

? ? 所有同步任務(wù)都在??main thread?主線程?上執(zhí)行,形成一個?執(zhí)行棧(execution context stack)膊升,所有的任務(wù)都會被放到執(zhí)行棧等待主線程執(zhí)行怎炊;

? ? 執(zhí)行棧?采用的是?后進先出?的規(guī)則,當函數(shù)執(zhí)行的時候廓译,會被添加到棧的頂部评肆,當執(zhí)行棧執(zhí)行完成后,就會從棧頂移出非区,直到棧內(nèi)被清空瓜挽;

? ?主線程之外,存在一個任務(wù)隊列(task queue)征绸,在走主流程的時候久橙,如果碰到異步任務(wù)俄占,那么就在?任務(wù)隊列?中放置這個異步任務(wù);

????一旦?執(zhí)行棧?中所有?同步任務(wù)執(zhí)行完畢淆衷,系統(tǒng)就會讀取?任務(wù)隊列缸榄,看看里面存在哪些事件。那些對應(yīng)的異步任務(wù) 在異步任務(wù)有了結(jié)果后祝拯,將注冊的回調(diào)函數(shù)放入?任務(wù)隊列?中等待主線程空閑的時候(調(diào)用棧被清空)甚带,被讀取到棧內(nèi)等待主線程的執(zhí)行。

? ?任務(wù)隊列 Task Queue佳头,即隊列鹰贵,是一種先進先出的一種數(shù)據(jù)結(jié)構(gòu)。


宏任務(wù)和微任務(wù)

? ?????在 JavaScript 中康嘉,任務(wù)被分為兩種碉输,一種 宏任務(wù)(MacroTask),一種叫 微任務(wù)(MicroTask)凄鼻。

? ?????MacroTask(宏任務(wù))有:setTimeout腊瑟、setInterval、setImmediate块蚌、I/O闰非、UI Rendering

? ?????MicroTask(微任務(wù))有:Process.nextTick(Node獨有)、Promise峭范、Object.observe(廢棄)财松、MutationObserver

? ?? ??微任務(wù)和宏任務(wù)是綁定的,每個宏任務(wù)在執(zhí)行時纱控,會創(chuàng)建自己的微任務(wù)隊列辆毡。

? ??? ?宏任務(wù)結(jié)束后,會執(zhí)行渲染甜害,然后執(zhí)行下一個宏任務(wù)舶掖, 而微任務(wù)可以理解成在當前宏任務(wù)執(zhí)行后立即執(zhí)行的任務(wù)。

? ? ? ? 宏任務(wù) --> 微任務(wù) --> 渲染 --> 宏任務(wù) --> ......

? ???????微任務(wù)就是一個需要異步執(zhí)行的函數(shù)尔店,執(zhí)行時機是在主函數(shù)執(zhí)行結(jié)束之后眨攘、當前宏任務(wù)結(jié)束之前。?

? ??????當JavaScript執(zhí)??段腳本的時候嚣州,V8會為其創(chuàng)建?個全局執(zhí)行上下文鲫售,在創(chuàng)建全局執(zhí)行上下文的 同時,V8引擎也會在內(nèi)部創(chuàng)建?個?微任務(wù)隊列 來存放微任務(wù)该肴;

????????在當前宏任務(wù)執(zhí)行的過程中情竹,有時候會產(chǎn)生多個微任務(wù);如果在執(zhí)行微任務(wù)的過程中匀哄,產(chǎn)?了新的微任務(wù)秦效,同樣會將該微任務(wù)添加到微任務(wù)隊列中雏蛮,V8引擎?直循環(huán)執(zhí)行微任務(wù)隊列中的任務(wù),直到隊列為空才算執(zhí)行結(jié)束棉安,并不會推遲到下個宏任務(wù)中執(zhí)行底扳。

? ? ? ?總結(jié) :微任務(wù)和宏任務(wù)是綁定的,每個宏任務(wù)在執(zhí)行時贡耽,會創(chuàng)建自己的微任務(wù)隊列。


瀏覽器事件循環(huán)的進程模型

????執(zhí)行棧在執(zhí)行完?同步任務(wù)?后鹊汛,查看?執(zhí)行棧?是否為空蒲赂,如果執(zhí)行棧為空,就會去檢查?微任務(wù)?(microTask)隊列是否為空刁憋,如果為空的話滥嘴,就執(zhí)行 Task(宏任務(wù)),否則就一次性執(zhí)行完所有微任務(wù)至耻。

????每次單個宏任務(wù)?執(zhí)行完畢后若皱,檢查?微任務(wù)?(microTask) 隊列是否為空,如果不為空的話尘颓,會按照?先入先出 的規(guī)則全部執(zhí)行完微任務(wù)(microTask)后走触,設(shè)置?微任務(wù)(microTask)隊列為null,然后再執(zhí)行?宏任務(wù)疤苹,如此循環(huán)互广。

? ? 注意 :async/await 在底層轉(zhuǎn)換成了 promise 和 then 回調(diào)函數(shù),也就是說卧土,這是 promise 的語法糖惫皱。

? ??sync函數(shù)在await之前的代碼都是同步執(zhí)行的,可以理解為await之前的代碼屬于new Promise時傳入的代碼尤莺,await之后的所有代碼都是在Promise.then中的回調(diào)

? ? 總結(jié)

? ??每當一個 js 腳本運行的時候旅敷,都會先執(zhí)行script中的整體代碼;

????當執(zhí)行棧中的同步任務(wù)執(zhí)行完畢颤霎,就會執(zhí)行?微任務(wù)?中的第一個任務(wù)并推入執(zhí)行棧執(zhí)行媳谁,當執(zhí)行棧為空,則再次讀取執(zhí)行微任務(wù)捷绑,循環(huán)重復(fù)直到微任務(wù)列表為空韩脑;

? ??等到微任務(wù)列表為空,才會讀取宏任務(wù)中的第一個任務(wù)并推入執(zhí)行棧執(zhí)行粹污,當執(zhí)行棧為空則再讀取執(zhí)行微任務(wù)段多,微任務(wù)為空才再讀取執(zhí)行宏任務(wù),如此循環(huán)壮吩。


Nodejs 中的 Event Loop

? ? ? ?Node 中的 Event Loop 和瀏覽器中的是完全不相同的東西

Event Loop

? ? nodejs 的 event loop 分為 6 個階段进苍,每當進入某一個階段的時候加缘,都會從對應(yīng)的回調(diào)隊列中取出函數(shù)去執(zhí)行。當隊列為空或者執(zhí)行的回調(diào)函數(shù)數(shù)量到達系統(tǒng)設(shè)定的閾值觉啊,就會進入下一階段拣宏。

? ??????timers 階段:這個階段執(zhí)行timer(setTimeout、setInterval)的回調(diào)

? ??????I/O callbacks 階段:執(zhí)行一些系統(tǒng)調(diào)用錯誤杠人,比如網(wǎng)絡(luò)通信的錯誤回調(diào)

? ??????idle, prepare 階段:僅node內(nèi)部使用

? ??????poll 階段:獲取新的I/O事件, 適當?shù)臈l件下node將阻塞在這里

? ??????check 階段:執(zhí)行?setImmediate()?的回調(diào)

? ??????close callbacks 階段:執(zhí)行?socket?的?close?事件回調(diào)

? ? 執(zhí)行順序

? ? ? ??一開始執(zhí)行棧的同步任務(wù)(宏任務(wù))執(zhí)行完畢后(將異步任務(wù)放入對應(yīng)的隊列)勋乾,再會先去執(zhí)行微任務(wù)(這點跟瀏覽器端的一樣, 這個過程中 先執(zhí)行?process.nextTick嗡善, 在執(zhí)行其他 微任務(wù)辑莫,process.nextTick 優(yōu)先級較高),接著進入 event loop 的 六個階段罩引,循環(huán)執(zhí)行各吨。

? ? ? ? 詳細的可以參看文檔?事件循環(huán)

????process.nextTick(微任務(wù))

????????這個函數(shù)其實是獨立于 Event Loop 之外的,它有一個自己的隊列袁铐,當每個階段完成后揭蜒,如果存在 nextTick 隊列,就會清空隊列中的所有回調(diào)函數(shù)剔桨,并且優(yōu)先于其他 microtask 執(zhí)行屉更。


? ? 瀏覽器 Event loop 和 nodejs Event loop 差異

? ??????瀏覽器環(huán)境下,microtask的任務(wù)隊列是每個macrotask執(zhí)行完之后執(zhí)行领炫。

網(wǎng)圖

? ??????在Node.js中偶垮,microtask 會在事件循環(huán)的各個階段之間執(zhí)行,也就是一個階段執(zhí)行完畢帝洪,就會去執(zhí)行microtask隊列的任務(wù)似舵。

網(wǎng)圖
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市葱峡,隨后出現(xiàn)的幾起案子砚哗,更是在濱河造成了極大的恐慌,老刑警劉巖砰奕,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蛛芥,死亡現(xiàn)場離奇詭異,居然都是意外死亡军援,警方通過查閱死者的電腦和手機仅淑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來胸哥,“玉大人涯竟,你說我怎么就攤上這事。” “怎么了庐船?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵银酬,是天一觀的道長。 經(jīng)常有香客問我筐钟,道長髓梅,這世上最難降的妖魔是什么坯苹? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任诅愚,我火速辦了婚禮瘪弓,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘纹因。我一直安慰自己喷屋,他們只是感情好,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布瞭恰。 她就那樣靜靜地躺著,像睡著了一般狱庇。 火紅的嫁衣襯著肌膚如雪惊畏。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天密任,我揣著相機與錄音颜启,去河邊找鬼。 笑死浪讳,一個胖子當著我的面吹牛缰盏,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播淹遵,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼口猜,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了透揣?” 一聲冷哼從身側(cè)響起济炎,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎辐真,沒想到半個月后须尚,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡侍咱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年耐床,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片楔脯。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡撩轰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情钧敞,我是刑警寧澤蜡豹,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站溉苛,受9級特大地震影響镜廉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜愚战,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一娇唯、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧寂玲,春花似錦塔插、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至断序,卻和暖如春流纹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背违诗。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工漱凝, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人诸迟。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓茸炒,卻偏偏與公主長得像,于是被迫代替她去往敵國和親阵苇。 傳聞我的和親對象是個殘疾皇子壁公,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345