瀏覽器&Node環(huán)境下的事件循環(huán)

什么是同步 / 異步任務(wù)?

發(fā)出調(diào)用,立即得到結(jié)果是為同步付燥;否則異步锈至。

Nodejs 運行機制

image.png

根據(jù)上圖簡單總結(jié):

  • 我們寫的 js 代碼交給 V8 處理
  • 解析后的代碼,調(diào)用Node API
  • 負責Node API的執(zhí)行担败。它將不同的任務(wù)分配給不同的線程,形成一個Event Loop(事件循環(huán)),以異步的方式將任務(wù)的執(zhí)行結(jié)果返回給V8引擎
  • V8引擎再將結(jié)果返回給用戶

個人理解:
node 啟動鼠渺,v8解析,執(zhí)行同步任務(wù)眷细;
異步任務(wù)通過node api(Node bindings)交給libuv執(zhí)行拦盹,注冊到對應的事件隊列
同步執(zhí)行完,進入事件循環(huán)

其中同步任務(wù)在v8執(zhí)行溪椎;異步任務(wù)系統(tǒng)內(nèi)核處理普舆,最后結(jié)果返回給v8,v8返回給應用

微任務(wù)執(zhí)行時機

Node環(huán)境:微任務(wù)在事件循環(huán)的各個階段的 空隙(中間)執(zhí)行
瀏覽器:微任務(wù)在事件循環(huán)的宏任務(wù)執(zhí)行完后執(zhí)行

<------microTasks
    ┌───────────────────────┐
┌─>│        timers         │
│  └──────────┬────────────┘
|             |            <----- microTasks
│  ┌──────────┴────────────┐
│  │     I/O callbacks     │
│  └──────────┬────────────┘
|             |            <----- microTasks
│  ┌──────────┴────────────┐
│  │     idle, prepare     │
│  └──────────┬────────────┘ 
|             |            <----- microTasks
|             |
|             |                   ┌───────────────┐
│  ┌──────────┴────────────┐      │   incoming:   │
│  │         poll          │<─────┤  connections, │
│  └──────────┬────────────┘      │   data, etc.  │
|             |                   └───────────────┘
|             |            <----- microTasks
│  ┌──────────┴────────────┐      
│  │        check          │
│  └──────────┬────────────┘
|             |            <----- microTasks
│  ┌──────────┴────────────┐
└──┤    close callbacks    │
    └───────────────────────┘

Libuv庫負責Node API的執(zhí)行校读。它將不同的任務(wù)分配給不同的線程沼侣,形成一個事件循環(huán), 以異步的方式將任務(wù)的執(zhí)行結(jié)果返回給V8引擎歉秫《曷澹可以簡單用下面這張圖來表示。

每一個I/O都需要一個回調(diào)函數(shù)——一旦執(zhí)行完便推到事件循環(huán)上用于執(zhí)行。

2019-03-06-12:49:不能停轧膘,繼續(xù)~

Event Loop

主線程從 ”任務(wù)隊列” 中讀取事件钞螟,這個過程是循環(huán)不斷的,所以整個的這種 運行機制 又稱為Event Loop(事件循環(huán))谎碍。

渲染進程中的所有運行在主線程的任務(wù)都需要先添加到消息隊列中鳞滨,然后事件循環(huán)在按照順序執(zhí)行消息隊列的任務(wù)。比如:我點擊頁面的按鈕蟆淀,觸發(fā)一段 JS 邏輯拯啦,然后進行異步網(wǎng)絡(luò)請求。

瀏覽器進程:將鼠標點擊通過 IPC 機制通知到渲染進程的 I/O 線程扳碍;
I / O 線程:將鼠標點擊事件加入到消息隊列提岔;
主線程:當主線程執(zhí)行完當前的任務(wù)之后,通過事件循環(huán)笋敞,取出消息隊列的點擊事件執(zhí)行碱蒙;
JS 線程:執(zhí)行點擊事件的 JS 邏輯,將 JS 邏輯中的同步代碼加入執(zhí)行棧中執(zhí)行夯巷;
網(wǎng)絡(luò)進程:當遇到需要異步網(wǎng)絡(luò)請求時赛惩,主線程將異步網(wǎng)絡(luò)請求通過 IPC 通訊交給網(wǎng)絡(luò)進程去執(zhí)行,并繼續(xù)執(zhí)行執(zhí)行棧中的同步代碼(相當于同步代碼和異步請求在同時執(zhí)行)趁餐;
網(wǎng)絡(luò)進程:當異步網(wǎng)絡(luò)資源加載完成喷兼,網(wǎng)絡(luò)進程通過 IPC 通訊通知到通知到渲染進程,將異步網(wǎng)絡(luò)回調(diào)加入到消息隊列后雷;
主線程:主線程將同步代碼執(zhí)行完成了季惯,通過事件循環(huán)取出消息隊列中的異步網(wǎng)絡(luò)回調(diào)放入執(zhí)行棧接著執(zhí)行。

通過不斷循環(huán)去取出異步回調(diào)來執(zhí)行(存在一個執(zhí)行循環(huán)來檢測任務(wù)隊列是否有新的任務(wù))臀突,這個過程就是事件循環(huán)勉抓。

image.png

關(guān)鍵字:主線程(會形成執(zhí)行棧)、隊列任務(wù)候学、“主完異進”

其它相關(guān)

js本身執(zhí)行是單線程的藕筋,也就是說當前代碼執(zhí)行的時候,是會阻塞其他代碼執(zhí)行的梳码。
但是js的運行環(huán)境隐圾,譬如瀏覽器本身是多線程執(zhí)行的,包括javascript引擎線程掰茶,界面渲染線程暇藏,瀏覽器事件觸發(fā)線程,Http請求線程等濒蒋。

一道經(jīng)典的前端面試題

for(var i = 0; i < 5; i ++) {
    setTimeout(function() {
        console.log(i);
    }, 0);
}

輸出5個5叨咖,為什么呢?

因為setTimeout的任務(wù)是異步的,js執(zhí)行棧(JS引擎中負責解釋和執(zhí)行JavaScript代碼的線程甸各,可以成為主線程)在執(zhí)行完js代碼后,才會去從消息隊列里面取消息焰坪、執(zhí)行消息趣倾,再取消息、再執(zhí)行某饰。當消息隊列為空時儒恋,就會等待直到消息隊列變成非空。
所以上面的代碼中黔漂,for循環(huán)執(zhí)行完畢之后诫尽,setTimeout里頭的回調(diào)函數(shù)才會被調(diào)用。那個時候i已經(jīng)變成了5炬守,因為放入了5個定時器牧嫉,所以會輸出5個5。

js執(zhí)行棧

JavaScript是單線程執(zhí)行的减途,無法同時執(zhí)行多段代碼酣藻。當某一段代碼正在執(zhí)行的時候,所有后續(xù)的任務(wù)都必須等待鳍置,形成一個隊列辽剧。一旦當前任務(wù)執(zhí)行完畢,再從隊列中取出下一個任務(wù)税产,這也常被稱為 “阻塞式執(zhí)行”怕轿。所以一次鼠標點擊,或是計時器到達時間點辟拷,或是Ajax請求完成觸發(fā)了回調(diào)函數(shù)撞羽,這些事件處理程序或回調(diào)函數(shù)都不會立即運行,而是立即排隊梧兼,一旦線程有空閑就執(zhí)行放吩。假如當前 JavaScript線程正在執(zhí)行一段很耗時的代碼,此時發(fā)生了一次鼠標點擊羽杰,那么事件處理程序就被阻塞渡紫,用戶也無法立即看到反饋,事件處理程序會被放入任務(wù)隊列考赛,直到前面的代碼結(jié)束以后才會開始執(zhí)行惕澎。如果代碼中設(shè)定了一個 setTimeout,那么瀏覽器便會在合適的時間颜骤,將代碼插入任務(wù)隊列唧喉,如果這個時間設(shè)為 0,就代表立即插入隊列,但不是立即執(zhí)行八孝,仍然要等待前面代碼執(zhí)行完畢董朝。所以 setTimeout 并不能保證執(zhí)行的時間,是否及時執(zhí)行取決于 JavaScript 線程是擁擠還是空閑干跛。

也就是說setTimeout只能保證在指定的時間過后將任務(wù)(需要執(zhí)行的函數(shù))插入隊列等候子姜,并不保證這個任務(wù)在什么時候執(zhí)行。執(zhí)行javascript的線程會在空閑的時候楼入,自行從隊列中取出任務(wù)然后執(zhí)行它哥捕。javascript通過這種隊列機制,給我們制造一個異步執(zhí)行的假象嘉熊。

部分引用來自:https://blog.csdn.net/qq_36995542/article/details/80007381

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末遥赚,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子阐肤,更是在濱河造成了極大的恐慌凫佛,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泽腮,死亡現(xiàn)場離奇詭異御蒲,居然都是意外死亡,警方通過查閱死者的電腦和手機诊赊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門厚满,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人碧磅,你說我怎么就攤上這事碘箍。” “怎么了鲸郊?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵丰榴,是天一觀的道長。 經(jīng)常有香客問我秆撮,道長四濒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任职辨,我火速辦了婚禮盗蟆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘舒裤。我一直安慰自己喳资,他們只是感情好,可當我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布腾供。 她就那樣靜靜地躺著仆邓,像睡著了一般鲜滩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上节值,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天徙硅,我揣著相機與錄音,去河邊找鬼察署。 笑死闷游,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的贴汪。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼休吠,長吁一口氣:“原來是場噩夢啊……” “哼扳埂!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起瘤礁,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤阳懂,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后柜思,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體岩调,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年赡盘,在試婚紗的時候發(fā)現(xiàn)自己被綠了号枕。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡陨享,死狀恐怖葱淳,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情抛姑,我是刑警寧澤赞厕,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站定硝,受9級特大地震影響皿桑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蔬啡,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一诲侮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧星爪,春花似錦浆西、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽诺核。三九已至,卻和暖如春久信,著一層夾襖步出監(jiān)牢的瞬間窖杀,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工裙士, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留入客,地道東北人。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓腿椎,卻偏偏與公主長得像桌硫,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子啃炸,可洞房花燭夜當晚...
    茶點故事閱讀 43,486評論 2 348

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