hey,你的Event Loop

瀏覽器中的Event Loop

參考資料:并發(fā)模型與事件循環(huán)-MDN
JavaScript 運行機(jī)制詳解:再談Event Loop@阮老師

我們都知道JavaScript是單線程的,也就是說同一時間只能干一件事。這是因為JavaScript主要是用來操作DOM的,如果變成多線程,瀏覽器就懵逼了,不知道該聽誰的了。但是雖然js是單線程,但是完全可以模擬多線程,靠的就是Event Loop

我們都知道js中的代碼分 同步異步,所謂的 異步 其實就是不會阻塞我們的主線程,等待主線程的代碼執(zhí)行完畢才會執(zhí)行。callback setTimeout setInterval Promise ... 這些都是都是我們耳熟能詳?shù)?異步 代碼


hey,你的Event Loop的圖1

如圖所示,js中的內(nèi)存分為 堆內(nèi)存(heap)棧內(nèi)存(stack), 堆內(nèi)存 中存的是我們聲明的object類型的數(shù)據(jù),棧內(nèi)存 中存的是 基本數(shù)據(jù)類型 以及 函數(shù)執(zhí)行時的運行空間。我們的 同步 代碼就放在 執(zhí)行棧 中,那異步代碼呢?瀏覽器會將 dom事件 ajax setTimeout等異步代碼放到隊列中,等待執(zhí)行棧中的代碼都執(zhí)行完畢,才會執(zhí)行隊列中的代碼,是不是有點像發(fā)布訂閱模式。


console.log(1); setTimeout(() => {     console.log(2);     }, 0); console.log(3); 復(fù)制代碼

根據(jù)之前說的,setTimeout 會被放到隊列中,等待執(zhí)行棧中的代碼執(zhí)行完畢才會執(zhí)行,所以會輸出1, 3, 2


但是異步代碼也是有區(qū)別的:

console.log(1) setTimeout(() => {     console.log(2) }, 0) Promise.resolve().then(() => {     console.log(3) }) 復(fù)制代碼

輸出的永遠(yuǎn)是1, 3, 2, 也就是說 promisesetTimeout 之前執(zhí)行了。這是因為 異步任務(wù) 分為 微任務(wù)(microtask)宏任務(wù)(task),執(zhí)行的順序是 執(zhí)行棧中的代碼 => 微任務(wù) => 宏任務(wù)


執(zhí)行棧

  • 執(zhí)行棧中的代碼永遠(yuǎn)最先執(zhí)行

微任務(wù)(microtask): promise MutationObserver...

  • 當(dāng)執(zhí)行棧中的代碼執(zhí)行完畢,會在執(zhí)行宏任務(wù)隊列之前先看看微任務(wù)隊列中有沒有任務(wù),如果有會先將微任務(wù)隊列中的任務(wù)清空才會去執(zhí)行宏任務(wù)隊列

宏任務(wù)(task): setTimeout setInterval setImmediate(IE專用) messageChannel...

  • 等待執(zhí)行棧微任務(wù)隊列都執(zhí)行完畢才會執(zhí)行,并且在執(zhí)行完每一個宏任務(wù)之后,會去看看微任務(wù)隊列有沒有新添加的任務(wù),如果有,會先將微任務(wù)隊列中的任務(wù)清空,才會繼續(xù)執(zhí)行下一個宏任務(wù)


setTimeout(() => {     console.log('timeout1')     Promise.resolve().then(() => {         console.log('promise1')     })     Promise.resolve().then(() => {         console.log('promise2')     }) }, 100) setTimeout(() => {     console.log('timeout2')     Promise.resolve().then(() => {         console.log('promise3')     }) }, 200) 復(fù)制代碼
  1. 先將兩個setTimeout塞到宏任務(wù)隊列中

  2. 當(dāng)?shù)谝粋€setTimeout1時間到了執(zhí)行的時候,首先打印timeout1,然后在微任務(wù)隊列中塞入promise1promise2

  3. 當(dāng)?shù)谝粋€setTimeout1執(zhí)行完畢后,會去微任務(wù)隊列檢查是不是空的,他發(fā)現(xiàn)了有兩個promise,會把兩個promise按順序執(zhí)行完再去執(zhí)行下一個宏任務(wù)

  4. 兩個promise執(zhí)行完畢后會微任務(wù)隊列中沒有任務(wù)了,會去宏任務(wù)中執(zhí)行下一個任務(wù) setTimeout2

  5. 當(dāng)setTimeout2 執(zhí)行的時候,先打印一個timeout2,然后又在微任務(wù)隊列中塞了一個promise2

  6. 當(dāng)setTimeout2執(zhí)行完畢后會去微任務(wù)隊列檢查,發(fā)現(xiàn)有一個promise2,會將promise2執(zhí)行

  7. 會依次打印 timeout1 promise1 promise2 timeout2 promise3


Node中的Event Loop

參考資料:libuv Node文檔

我們都知道Node.js 是一個基于 Chrome V8 引擎的 JavaScript 運行環(huán)境,也就是能夠讓js在服務(wù)端運行。但是Node中的Event Loop是用libuv模擬的,它將不同的任務(wù)分配給不同的線程,形成一個Event Loop,以異步的方式將任務(wù)的執(zhí)行結(jié)果返回給V8引擎。


  • Node中的微任務(wù):process.nextTric promise setImmediate...

  • Node中的宏任務(wù):setTimeout setInterval...


hey,你的Event Loop的圖2


  • timers:執(zhí)行setTimeout() 和 setInterval()中到期的callback。

  • I/O callbacks:上一輪循環(huán)中有少數(shù)的I/Ocallback會被延遲到這一輪的這一階段執(zhí)行

  • idle, prepare:僅內(nèi)部使用

  • poll:最為重要的階段,執(zhí)行I/O   callback,檢查有沒有timers到期 timer在適當(dāng)?shù)臈l件下會阻塞在這個階段

  • check:執(zhí)行setImmediate的callback

  • close callbacks:執(zhí)行close事件的callback,例如socket.on("close",func)


Node中的Event Loop會在每次切換隊列的時候 清空微任務(wù)隊列,也就會會將當(dāng)前隊列都執(zhí)行完,在進(jìn)入下一階段的時候檢查一下微任務(wù)中有沒有任務(wù)

setTimeout(() => {     console.log('timeout1')     Promise.resolve().then(() => {         console.log('promise1')     })     Promise.resolve().then(() => {         console.log('promise2')     }) }, 0) setTimeout(() => {     console.log('timeout2')     Promise.resolve().then(() => {         console.log('promise3')     }) }, 0) 復(fù)制代碼
  1. 先將兩個setTimeout塞到宏任務(wù)隊列中

  2. 當(dāng)?shù)谝粋€setTimeout1時間到了執(zhí)行的時候,首先打印timeout1,然后在微任務(wù)隊列中塞入promise1promise2

  3. 當(dāng)?shù)谝粋€setTimeout1執(zhí)行完畢后,繼續(xù)執(zhí)行下一個setTimeout2

  4. 當(dāng)setTimeout2 執(zhí)行的時候,先打印一個timeout2,然后又在微任務(wù)隊列中塞了一個promise2

  5. 當(dāng)前宏任務(wù)隊列清空,進(jìn)入下一階段,去檢查微任務(wù)隊列中有沒有任務(wù)

  6. 清空微任務(wù)隊列

  7. 在node環(huán)境中執(zhí)行 會依次打印 timeout1 timeout2 promise1 promise2 promise3


作者:asdff
來源:掘金

登錄后免費查看全文
立即登錄
App下載
技術(shù)鄰APP
工程師必備
  • 項目客服
  • 培訓(xùn)客服
  • 平臺客服

TOP