瀏覽器中的事件循環(huán)和nodejs中的事件循環(huán)

首先 setTimeout 并沒有特殊,也是一個(gè) task脯厨。另外每次的執(zhí)行過 task 和 大量的 microtask(不一定在一次循環(huán)全執(zhí)行完)后,會進(jìn)行 renderUi 階段,雖然不是每次事件循環(huán)都進(jìn)行 renderUi ,但每次間隔叠聋,也就是傳說中 60hz 的一幀 16ms。

瀏覽器中的事件循環(huán)

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

同步代碼的執(zhí)行也屬于宏任務(wù)

瀏覽器先執(zhí)行同步代碼受裹,遇到宏任務(wù)就放到 macro task 的任務(wù)隊(duì)列中碌补,遇到微任務(wù)就放入 micro task 的隊(duì)列中。在執(zhí)行完同步任務(wù)之后就會先執(zhí)行微任務(wù)隊(duì)列中的所有微任務(wù)棉饶,然后從宏任務(wù)隊(duì)列中取出第一個(gè)宏任務(wù)執(zhí)行厦章,執(zhí)行完畢之后再去執(zhí)行所有的微任務(wù)...這個(gè)過程是循環(huán)不斷的所以被稱為事件循環(huán)。但是需要注意的是瀏覽器會在每 16ms 進(jìn)行一次的 UI 渲染照藻,可能會中斷事件循環(huán)的執(zhí)行

常見的宏任務(wù)

setTimeout袜啃、setInterval、 setImmediate岩梳、script(整體代碼)囊骤、 I/O 操作晃择、UI 渲染

常見的微任務(wù)

MutationObserver Promise

nodejs 中的事件循環(huán)

外部輸入數(shù)據(jù)–>輪詢階段(poll)–>檢查階段(check) setImmediate–>關(guān)閉事件回調(diào)階段(close callback)–>定時(shí)器檢測階段(timer) setTimeout/setInterval–>I/O 事件回調(diào)階段(I/O callbacks) 文件操作的回調(diào)函數(shù)等等–>閑置階段(idle, prepare)–>輪詢階段(按照該順序反復(fù)運(yùn)行)

我們可以接觸到的比較常用的就是 poll,check,timer 這幾個(gè)階段

nodejs中時(shí)間循環(huán)和瀏覽器中的區(qū)別

在 node11 版本之后冀值,對于 macro task 和 micro task 的執(zhí)行時(shí)機(jī)和瀏覽器中相同。

在 node11 之前宫屠,nodejs 和瀏覽器中的事件循環(huán)的區(qū)別就是 micro task 的執(zhí)行時(shí)機(jī)列疗;nodejs中 timers 階段有幾個(gè) setTimeout/setInterval 都會依次執(zhí)行,執(zhí)行完畢所有的 timers 代碼之后才會去執(zhí)行 micro task浪蹂,并不像瀏覽器端抵栈,每執(zhí)行一個(gè)宏任務(wù)后就去執(zhí)行所有微任務(wù)告材。

所以下面的代碼,在 node11 之前的執(zhí)行結(jié)果是和瀏覽器中不相同的

console.log('start')
setTimeout(() => {
  console.log('timer1')
  Promise.resolve().then(function() {
    console.log('promise1')
  })
}, 0)
setTimeout(() => {
  console.log('timer2')
  Promise.resolve().then(function() {
    console.log('promise2')
  })
}, 0)
Promise.resolve().then(function() {
  console.log('promise3')
})
console.log('end')
//start=>end=>promise3=>timer1=>timer2=>promise1=>promise2
// 瀏覽器和新版本node start=>end=>promise3=>timer1=>promise1=>timer2=>promise2

poll階段 該階段會執(zhí)行所有的回調(diào)

poll 是一個(gè)至關(guān)重要的階段古劲,這一階段中斥赋,系統(tǒng)會做兩件事情

  1. 回到 timer 階段執(zhí)行回調(diào)

  2. 執(zhí)行 I/O 回調(diào)

沒有設(shè)置timer或者是設(shè)置的timer沒有到時(shí)間

會發(fā)生以下兩件事情

  1. 如果 poll 隊(duì)列不為空,會遍歷回調(diào)隊(duì)列并同步執(zhí)行产艾,直到隊(duì)列為空或者達(dá)到系統(tǒng)限制

  2. 如果 poll 隊(duì)列為空時(shí)疤剑,會有兩件事發(fā)生

如果有 setImmediate 回調(diào)需要執(zhí)行,poll 階段會停止并且進(jìn)入到 check 階段執(zhí)行回調(diào)

如果沒有 setImmediate 回調(diào)需要執(zhí)行闷堡,會等待回調(diào)被加入到隊(duì)列中并立即執(zhí)行回調(diào)隘膘,這里同樣會有個(gè)超時(shí)時(shí)間設(shè)置防止一直等待下去

設(shè)置了timer且timer時(shí)間已經(jīng)到了

當(dāng)然設(shè)定了 timer 的話且 poll 隊(duì)列為空,則會判斷是否有 timer 超時(shí)杠览,如果有的話會回到 timer 階段執(zhí)行回調(diào)弯菊。

注意點(diǎn)

(1) setTimeout 和 setImmediate

二者非常相似,區(qū)別主要在于調(diào)用時(shí)機(jī)不同踱阿。

setImmediate 設(shè)計(jì)在 poll 階段完成時(shí)執(zhí)行管钳,即 check 階段;

setTimeout 設(shè)計(jì)在 poll 階段為空閑時(shí)扫茅,且設(shè)定時(shí)間到達(dá)后執(zhí)行蹋嵌,但它在 timer 階段執(zhí)行

setTimeout(function timeout () {
  console.log('timeout');
},0);
setImmediate(function immediate () {
  console.log('immediate');
});

對于以上代碼來說,setTimeout 可能執(zhí)行在前葫隙,也可能執(zhí)行在后栽烂。

首先 setTimeout(fn, 0) === setTimeout(fn, 1),這是由源碼決定的

我們發(fā)現(xiàn)雖然我們傳的超時(shí)時(shí)間是 0恋脚,但是 0 不是合法值腺办,nodejs 會把超時(shí)時(shí)間變成 1。

進(jìn)入事件循環(huán)也是需要成本的糟描,如果在準(zhǔn)備時(shí)候花費(fèi)了大于 1ms 的時(shí)間怀喉,那么在 timer 階段就會直接執(zhí)行 setTimeout 回調(diào)

如果準(zhǔn)備時(shí)間花費(fèi)小于 1ms,那么就是 setImmediate 回調(diào)先執(zhí)行了

但當(dāng)二者在異步 i/o callback 內(nèi)部調(diào)用時(shí)船响,總是先執(zhí)行 setImmediate躬拢,再執(zhí)行 setTimeout

const fs = require('fs')
fs.readFile(__filename, () => {
    setTimeout(() => {
        console.log('timeout');
    }, 0)
    setImmediate(() => {
        console.log('immediate')
    })
})
// immediate
// timeout

在上述代碼中,setImmediate 永遠(yuǎn)先執(zhí)行见间。因?yàn)閮蓚€(gè)代碼寫在 IO 回調(diào)中聊闯,IO 回調(diào)是在 poll 階段執(zhí)行,當(dāng)回調(diào)執(zhí)行完畢后隊(duì)列為空米诉,發(fā)現(xiàn)存在 setImmediate 回調(diào)菱蔬,所以就直接跳轉(zhuǎn)到 check 階段去執(zhí)行回調(diào)了。

(2) process.nextTick

這個(gè)函數(shù)其實(shí)是獨(dú)立于 Event Loop 之外的,它有一個(gè)自己的隊(duì)列拴泌,當(dāng)每個(gè)階段完成后魏身,如果存在 nextTick 隊(duì)列,就會清空隊(duì)列中的所有回調(diào)函數(shù)蚪腐,并且優(yōu)先于其他 microtask 執(zhí)行箭昵。

setTimeout(() => {
 console.log('timer1')
 Promise.resolve().then(function() {
   console.log('promise1')
 })
}, 0)
process.nextTick(() => {
 console.log('nextTick')
 process.nextTick(() => {
   console.log('nextTick')
   process.nextTick(() => {
     console.log('nextTick')
     process.nextTick(() => {
       console.log('nextTick')
     })
   })
 })
})
// nextTick=>nextTick=>nextTick=>nextTick=>timer1=>promise1
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市回季,隨后出現(xiàn)的幾起案子宙枷,更是在濱河造成了極大的恐慌,老刑警劉巖茧跋,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件慰丛,死亡現(xiàn)場離奇詭異,居然都是意外死亡瘾杭,警方通過查閱死者的電腦和手機(jī)诅病,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來粥烁,“玉大人贤笆,你說我怎么就攤上這事√肿瑁” “怎么了芥永?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長钝吮。 經(jīng)常有香客問我埋涧,道長,這世上最難降的妖魔是什么奇瘦? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任棘催,我火速辦了婚禮,結(jié)果婚禮上耳标,老公的妹妹穿的比我還像新娘醇坝。我一直安慰自己,他們只是感情好次坡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布呼猪。 她就那樣靜靜地躺著,像睡著了一般砸琅。 火紅的嫁衣襯著肌膚如雪宋距。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天明棍,我揣著相機(jī)與錄音乡革,去河邊找鬼寇僧。 笑死摊腋,一個(gè)胖子當(dāng)著我的面吹牛沸版,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播兴蒸,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼视粮,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了橙凳?” 一聲冷哼從身側(cè)響起蕾殴,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎岛啸,沒想到半個(gè)月后钓觉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡坚踩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年荡灾,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瞬铸。...
    茶點(diǎn)故事閱讀 39,727評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡批幌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出嗓节,到底是詐尸還是另有隱情荧缘,我是刑警寧澤,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布拦宣,位于F島的核電站截粗,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏鸵隧。R本人自食惡果不足惜桐愉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望掰派。 院中可真熱鬧从诲,春花似錦、人聲如沸靡羡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽略步。三九已至描扯,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間趟薄,已是汗流浹背绽诚。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人恩够。 一個(gè)月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓卒落,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蜂桶。 傳聞我的和親對象是個(gè)殘疾皇子儡毕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評論 2 354

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