事件循環(huán)機(jī)制(Event loop)宏任務(wù)(macro-task)微任務(wù)(micro-task)

前言:

首先我們先回顧一下幾個簡單的知識點

1 進(jìn)程與線程的關(guān)系

進(jìn)程:程序的一次執(zhí)行拢操,他占有一片獨有的內(nèi)存空間

線程:CPU的基本調(diào)度單位莹痢,是程序執(zhí)行的一個完整流程

關(guān)系:

一個進(jìn)程中一般至少有一個運行的線程——主線程

一個進(jìn)程中也可以同時運行多個線程

多個進(jìn)程之間的數(shù)據(jù)是不能同時直接共享的

2 JS 是單線程還是多線程琼娘?

先看一段代碼塊


// 最后執(zhí)行順序 結(jié)果: 正常1预侯,f2 嗤攻,正常2腺怯,f1袱饭,定時器;

眾所周知:JS是一門單線程語言 就像上面的代碼塊 任務(wù)是一個一個列隊的形式被調(diào)用的

在最新的HTML5中提出了Web-Worker呛占,但javascript是單線程這一核心仍未改變虑乖。

既然js是單線程?那就像只有一個窗口的銀行,客戶需要排隊一個一個辦理業(yè)務(wù)晾虑,同理js任務(wù)也要一個一個順序執(zhí)行疹味。如果一個任務(wù)耗時過長,那么后一個任務(wù)也必須等著

3 為什么js是單線程的帜篇?

假設(shè)JS是多線程的 會發(fā)生什么

試想一下 如果javascript是多線程的糙捺,那么當(dāng)兩個線程同時對dom進(jìn)行一項操作,

例如一個向其添加事件笙隙,而另一個刪除了這個dom洪灯,此時該如何處理呢?

因此竟痰,為了保證不會 發(fā)生類似于這個例子中的情景签钩,javascript選擇只用一個主線程來執(zhí)行代碼掏呼,這樣就保證了程序執(zhí)行的一致性。

4 那么既然是單線程 為什么定時器可以沒有按照順序執(zhí)行呢铅檩?

為什么在接口請求的時候 可以同時發(fā)起多個請求呢憎夷?

這里就涉及到 同步和異步情況這也正是我們今天的重點內(nèi)容,事件循環(huán)機(jī)制(event loop)

?帶著這個問題 我們進(jìn)入下面的內(nèi)容

正文:

1.執(zhí)行棧與事件隊列

執(zhí)行棧:當(dāng)我們調(diào)用一個方法的時候昧旨,js會生成一個與這個方法對應(yīng)的執(zhí)行環(huán)境(context)拾给,又叫執(zhí)行上下文。

這個執(zhí)行環(huán)境中存在著這個方法的私有作用域兔沃,上層作用域的指向蒋得,方法的參數(shù),這個作用域中定義的變量以及這個作用域的this對象粘拾。

而當(dāng)一系列方法被依次調(diào)用的時候窄锅,因為js是單線程的,同一時間只能執(zhí)行一個方法缰雇,于是這些方法被排隊在一個單獨的地方。這個地方被稱為執(zhí)行棧追驴。

事件隊列:當(dāng)一個腳本第一次執(zhí)行的時候械哟,js引擎會解析這段代碼,并將其中的同步代碼按照執(zhí)行順序加入執(zhí)行棧中殿雪,然后從頭開始執(zhí)行暇咆。

如果當(dāng)前執(zhí)行的是一個方法,那么js會向執(zhí)行棧中添加這個方法的執(zhí)行環(huán)境丙曙,然后進(jìn)入這個執(zhí)行環(huán)境繼續(xù)執(zhí)行其中的代碼爸业。

當(dāng)這個執(zhí)行環(huán)境中的代碼 執(zhí)行完畢并返回結(jié)果后,js會退出這個執(zhí)行環(huán)境并把這個執(zhí)行環(huán)境銷毀亏镰,回到上一個方法的執(zhí)行環(huán)境扯旷。

這個過程反復(fù)進(jìn)行,直到執(zhí)行棧中的代碼全部執(zhí)行完畢索抓。

一個方法執(zhí)行會向執(zhí)行棧中加入這個方法的執(zhí)行環(huán)境钧忽,在這個執(zhí)行環(huán)境中還可以調(diào)用其他方法,甚至是自己逼肯,其結(jié)果不過是在執(zhí)行棧中再添加一個執(zhí)行環(huán)境耸黑。

這個過程可以是無限進(jìn)行下去的,除非發(fā)生了棧溢出篮幢,即超過了所能使用內(nèi)存的最大值大刊。(這就是為什么遞歸容易出現(xiàn)棧溢出的原因)

以上的過程說的都是同步代碼的執(zhí)行。那么當(dāng)一個異步代碼(如發(fā)送ajax請求數(shù)據(jù))執(zhí)行后會如何呢三椿?

js引擎遇到一個異步事件后并不會一直等待其返回結(jié)果缺菌,而是會將這個事件掛起葫辐,繼續(xù)執(zhí)行執(zhí)行棧中的其他任務(wù)。

當(dāng)一個異步事件返回結(jié)果后男翰,js會將這個事件加入與當(dāng)前執(zhí)行棧不同的另一個隊列另患,我們稱之為事件隊列。

事件循環(huán):?被放入事件隊列不會立刻執(zhí)行其回調(diào)蛾绎,而是等待當(dāng)前執(zhí)行棧中的所有任務(wù)都執(zhí)行完畢昆箕, 主線程處于閑置狀態(tài)時,主線程會去查找事件隊列是否有任務(wù)租冠。

如果有鹏倘,那么主線程會從中取出排在第一位的事件,并把這個事件對應(yīng)的回調(diào)放入執(zhí)行棧中顽爹,然后執(zhí)行其中的同步代碼...纤泵,如此反復(fù),

這樣就形成了一個無限的循環(huán)镜粤。這就是這個過程被稱為?事件循環(huán)(Event Loop)捏题;


在代碼執(zhí)行的時候 是先執(zhí)行同步代碼?再執(zhí)行異步代碼的;

圖上標(biāo)志的JS模塊肉渴,是我們編寫的代碼公荧。

按照順序執(zhí)行完后(即同步代碼執(zhí)行完),

其代碼里定時器的回調(diào)函數(shù)同规,Dom事件的回調(diào)函數(shù)循狰,Ajax請求的回調(diào)函數(shù)等這些異步代碼,

會由瀏覽器WebAPIs管理模塊里的對應(yīng)模塊相應(yīng)管理券勺。當(dāng)這些回調(diào)函數(shù)绪钥,到達(dá)要執(zhí)行的條件(比如定時器到時間了,用戶點擊了)关炼,會由相應(yīng)的模塊送到隊列里程腹,然后執(zhí)行。

在列隊(callBack Queue)里面 -誰先放進(jìn)去盗扒,就誰先執(zhí)行;

接下來我們看下面一段代碼塊


分析:

定時器的第二個參數(shù)是0跪楞,即立馬放進(jìn)了隊列里,

Promise也是立馬達(dá)到了滿足條件侣灶。也會放進(jìn)隊列里甸祭,又根據(jù)代碼的先后執(zhí)行順序,隊列里肯定先放定時器的回調(diào)函數(shù)褥影,再放Promise的回調(diào)函數(shù)池户,

等同步代碼執(zhí)行完后,異步代碼就是先執(zhí)行定時器里回調(diào)函數(shù),再執(zhí)行Promise里的回調(diào)函數(shù)校焦∩薅叮控制臺輸出應(yīng)該是1 3 2才對啊U洹7昭!

可是為啥是 1 2 3 呢耸成?报亩??

這就引出了我們今天所學(xué)的第二個重點內(nèi)容井氢?宏任務(wù)(macro-task)與微任務(wù)(micro-task)

先看下面這個圖

**==** (ps:上圖的標(biāo)注的分線程是瀏覽器的弦追,不是我們的Js代碼的。我們只是寫的代碼交給了瀏覽器管理);

在圖里面我們可以看到隊列里又進(jìn)行了劃分花竞,又分為宏隊列與微隊列

宏隊列里放的是宏任務(wù)

微隊列里放的是微任務(wù)

其Promise 和 Mutation(vue里會遇到mutation)里的回調(diào)函數(shù)劲件,會放進(jìn)微對列

微隊列優(yōu)先級是高于宏隊列優(yōu)先級

so: 這個就可以解釋上線的代碼塊輸出的是 1 2 3了

下面我們再看一段代碼塊


因為:每執(zhí)行一個宏任務(wù)時,都會檢查微隊列中是否有待執(zhí)行的的回調(diào)约急,優(yōu)先執(zhí)行微任務(wù) 也就是微任務(wù)是可以插隊的

結(jié)尾:

javascrit的事件循環(huán)是這門語言中非常重要且基礎(chǔ)的概念零远。

清楚的了解了事件循環(huán)的執(zhí)行順序和每一個階段的特點,可以使我們對一段異步代碼的執(zhí)行順序有一個清晰的認(rèn)識厌蔽,

從而減少代碼運行的不確定性遍烦。合理的使用各種延遲事件的方法,有助于代碼更好的按照其優(yōu)先級去執(zhí)行躺枕。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市供填,隨后出現(xiàn)的幾起案子拐云,更是在濱河造成了極大的恐慌,老刑警劉巖近她,帶你破解...
    沈念sama閱讀 216,843評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件叉瘩,死亡現(xiàn)場離奇詭異,居然都是意外死亡粘捎,警方通過查閱死者的電腦和手機(jī)薇缅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,538評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來攒磨,“玉大人泳桦,你說我怎么就攤上這事∶溏郑” “怎么了灸撰?”我有些...
    開封第一講書人閱讀 163,187評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我浮毯,道長完疫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,264評論 1 292
  • 正文 為了忘掉前任债蓝,我火速辦了婚禮壳鹤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘饰迹。我一直安慰自己芳誓,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,289評論 6 390
  • 文/花漫 我一把揭開白布蹦锋。 她就那樣靜靜地躺著兆沙,像睡著了一般。 火紅的嫁衣襯著肌膚如雪莉掂。 梳的紋絲不亂的頭發(fā)上葛圃,一...
    開封第一講書人閱讀 51,231評論 1 299
  • 那天,我揣著相機(jī)與錄音憎妙,去河邊找鬼库正。 笑死,一個胖子當(dāng)著我的面吹牛厘唾,可吹牛的內(nèi)容都是我干的褥符。 我是一名探鬼主播,決...
    沈念sama閱讀 40,116評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼抚垃,長吁一口氣:“原來是場噩夢啊……” “哼喷楣!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起鹤树,我...
    開封第一講書人閱讀 38,945評論 0 275
  • 序言:老撾萬榮一對情侶失蹤铣焊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后罕伯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體曲伊,經(jīng)...
    沈念sama閱讀 45,367評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,581評論 2 333
  • 正文 我和宋清朗相戀三年追他,在試婚紗的時候發(fā)現(xiàn)自己被綠了坟募。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,754評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡邑狸,死狀恐怖懈糯,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情推溃,我是刑警寧澤昂利,帶...
    沈念sama閱讀 35,458評論 5 344
  • 正文 年R本政府宣布届腐,位于F島的核電站戚绕,受9級特大地震影響鹃两,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜聂儒,卻給世界環(huán)境...
    茶點故事閱讀 41,068評論 3 327
  • 文/蒙蒙 一扩所、第九天 我趴在偏房一處隱蔽的房頂上張望围详。 院中可真熱鬧,春花似錦祖屏、人聲如沸助赞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,692評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽雹食。三九已至,卻和暖如春期丰,著一層夾襖步出監(jiān)牢的瞬間群叶,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,842評論 1 269
  • 我被黑心中介騙來泰國打工钝荡, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留街立,地道東北人。 一個月前我還...
    沈念sama閱讀 47,797評論 2 369
  • 正文 我出身青樓埠通,卻偏偏與公主長得像赎离,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子端辱,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,654評論 2 354

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