小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

用一道大廠面試題帶你搞懂事件循環(huán)機制

 行者花雕 2020-08-18

本文涵蓋

  • 面試題的引入
  • 對事件循環(huán)面試題執(zhí)行順序的一些疑問
  • 通過面試題對微任務(wù)、事件循環(huán)、定時器等對深入理解
  • 結(jié)論總結(jié)

面試題

面試題如下,大家可以先試著寫一下輸出結(jié)果,然后再看我下面的詳細(xì)講解,看看會不會有什么出入,如果把整個順序弄清楚 Node.js 的執(zhí)行順序應(yīng)該就沒問題了。

async function async1(){    console.log('async1 start')    await async2()    console.log('async1 end')  }async function async2(){    console.log('async2')}console.log('script start')setTimeout(function(){    console.log('setTimeout0') },0)  setTimeout(function(){    console.log('setTimeout3') },3)  setImmediate(() => console.log('setImmediate'));process.nextTick(() => console.log('nextTick'));async1();new Promise(function(resolve){    console.log('promise1')    resolve();    console.log('promise2')}).then(function(){    console.log('promise3')})console.log('script end')

面試題正確的輸出結(jié)果

script startasync1 startasync2promise1promise2script endnextTickasync1 endpromise3setTimeout0setImmediatesetTimeout3

提出問題

在理解node.js的異步的時候有一些不懂的地方,使用node.js的開發(fā)者一定都知道它是單線程的,異步不阻塞且高并發(fā)的一門語言,但是node.js在實現(xiàn)異步的時候,兩個異步任務(wù)開啟了,是就是誰快就誰先完成這么簡單,還是說異步任務(wù)最后也會有一個先后執(zhí)行順序?對于一個單線程的的異步語言它是怎么實現(xiàn)高并發(fā)的呢?

好接下來我們就帶著這兩個問題來真正的理解node.js中的異步(微任務(wù)與事件循環(huán))。

Node 的異步語法比瀏覽器更復(fù)雜,因為它可以跟內(nèi)核對話,不得不搞了一個專門的庫 libuv 做這件事。這個庫負(fù)責(zé)各種回調(diào)函數(shù)的執(zhí)行時間,異步任務(wù)最后基于事件循環(huán)機制還是要回到主線程,一個個排隊執(zhí)行。

我自己是一名從事了多年開發(fā)的web前端老程序員,目前辭職在做自己的web前端私人定制課程,今年年初我花了一個月整理了一份最適合2019年學(xué)習(xí)的web前端學(xué)習(xí)干貨,各種框架都有整理,送給每一位前端小伙伴,想要獲取的可以關(guān)注我并添加我的web前端交流裙:600610151,即可免費獲取。

詳細(xì)講解

1.本輪循環(huán)與次輪循環(huán)

異步任務(wù)可以分成兩種。

  1. 追加在本輪循環(huán)的異步任務(wù)
  2. 追加在次輪循環(huán)的異步任務(wù)

所謂”循環(huán)”,指的是事件循環(huán)(event loop)。這是 JavaScript 引擎處理異步任務(wù)的方式,后文會詳細(xì)解釋。這里只要理解,本輪循環(huán)一定早于次輪循環(huán)執(zhí)行即可。

Node 規(guī)定,process.nextTick和Promise的回調(diào)函數(shù),追加在本輪循環(huán),即同步任務(wù)一旦執(zhí)行完成,就開始執(zhí)行它們。而setTimeout、setInterval、setImmediate的回調(diào)函數(shù),追加在次輪循環(huán)。

2.process.nextTick()

1)process.nextTick不要因為有next就被好多小伙伴當(dāng)作次輪循環(huán)。

2)Node 執(zhí)行完所有同步任務(wù),接下來就會執(zhí)行 process.nextTick 的任務(wù)隊列。

3)開發(fā)過程中如果想讓異步任務(wù)盡可能快地執(zhí)行,可以使用 process.nextTick 來完成。

3.微任務(wù)(microtack)

根據(jù)語言規(guī)格,Promise 對象的回調(diào)函數(shù),會進(jìn)入異步任務(wù)里面的”微任務(wù)”(microtask)隊列。

微任務(wù)隊列追加在 process.nextTick 隊列的后面,也屬于本輪循環(huán)。

根據(jù)語言規(guī)格,Promise 對象的回調(diào)函數(shù),會進(jìn)入異步任務(wù)里面的”微任務(wù)”(microtask)隊列。

微任務(wù)隊列追加在process.nextTick隊列的后面,也屬于本輪循環(huán)。所以,下面的代碼總是先輸出3,再輸出4。

process.nextTick(() => console.log(3));Promise.resolve().then(() => console.log(4));

// 輸出結(jié)果3,4

process.nextTick(() => console.log(1));Promise.resolve().then(() => console.log(2));process.nextTick(() => console.log(3));Promise.resolve().then(() => console.log(4));

// 輸出結(jié)果 1,3,2,4

注意,只有前一個隊列全部清空以后,才會執(zhí)行下一個隊列。兩個隊列的概念 nextTickQueue 和微隊列 microTaskQueue,也就是說開啟異步任務(wù)也分為幾種,像 Promise 對象這種,開啟之后直接進(jìn)入微隊列中,微隊列內(nèi)的就是那個任務(wù)快就那個先執(zhí)行完,但是針對于隊列與隊列之間不同的任務(wù),還是會有先后順序,這個先后順序是由隊列決定的。

4.事件循環(huán)的階段(idle, prepare忽略了這個階段)

事件循環(huán)最階段最詳細(xì)的講解(官網(wǎng):https:///en/docs/guides/event-loop-timers-and-nexttick/#setimmediate-vs-settimeout)

  1. timers階段次階段包括setTimeout()和setInterval()
  2. IO callbacks大部分的回調(diào)事件,普通的caollback
  3. poll階段網(wǎng)絡(luò)連接,數(shù)據(jù)獲取,讀取文件等操作
  4. check階段setImmediate()在這里調(diào)用回調(diào)
  5. close階段 一些關(guān)閉回調(diào),例如socket.on('close', ...)
  • 事件循環(huán)注意點

1)Node 開始執(zhí)行腳本時,會先進(jìn)行事件循環(huán)的初始化,但是這時事件循環(huán)還沒有開始,會先 完成下面的事情。

同步任務(wù) 發(fā)出異步請求 規(guī)劃定時器生效的時間 執(zhí)行process.nextTick()等等

最后,上面這些事情都干完了,事件循環(huán)就正式開始了。

2)事件循環(huán)同樣運行在單線程環(huán)境下,高并發(fā)也是依靠事件循環(huán),每產(chǎn)生一個事件,就會加入到該階段對應(yīng)的隊列中,此時事件循環(huán)將該隊列中的事件取出,準(zhǔn)備執(zhí)行之后的 Callback。

3)假設(shè)事件循環(huán)現(xiàn)在進(jìn)入了某個階段,即使這期間有其他隊列中的事件就緒,也會先將當(dāng)前隊列的全部回調(diào)方法執(zhí)行完畢后,再進(jìn)入到下一個階段。

5.事件循環(huán)中的setTimeOut與setImmediate

由于 setTimeout 在 timers 階段執(zhí)行,而 setImmediate 在 check 階段執(zhí)行。所以,setTimeout 會早于 setImmediate 完成。

setTimeout(() => console.log(1));setImmediate(() => console.log(2));

上面代碼應(yīng)該先輸出1,再輸出2,但是實際執(zhí)行的時候,結(jié)果卻是不確定,有時還會先輸出2,再輸出1。

這是因為 setTimeout 的第二個參數(shù)默認(rèn)為0。但是實際上,Node 做不到0毫秒,最少也需要1毫秒,根據(jù)官方文檔,第二個參數(shù)的取值范圍在1毫秒到2147483647毫秒之間。也就是說,setTimeout(f, 0)等同于setTimeout(f, 1)。

實際執(zhí)行的時候,進(jìn)入事件循環(huán)以后,有可能到了1毫秒,也可能還沒到1毫秒,取決于系統(tǒng)當(dāng)時的狀況。如果沒到1毫秒,那么 timers 階段就會跳過,進(jìn)入 check 階段,先執(zhí)行 setImmediate 的回調(diào)函數(shù)。

但是,下面的代碼一定是先輸出2,再輸出1。

const fs = require('fs');fs.readFile('test.js', () => { setTimeout(() => console.log(1)); setImmediate(() => console.log(2));});

上面代碼會先進(jìn)入 I/O callbacks 階段,然后是 check 階段,最后才是 timers 階段。因此,setImmediate才會早于setTimeout執(zhí)行。

6.同步任務(wù)中async以及promise的一些誤解

  • 問題1:

在面試題中,在同步任務(wù)的過程中,不知道大家有沒有疑問,為什么不是執(zhí)行完async2輸出后執(zhí)行async1 end輸出,而是接著執(zhí)行 promise1?

引用書中一句話:“ async 函數(shù)返回一個 Promise 對象,當(dāng)函數(shù)執(zhí)行的時候,一旦遇到 await 就會先返回,等到觸發(fā)的異步操作完成,再接著執(zhí)行函數(shù)體內(nèi)后面的語句。”

簡單的說,先去執(zhí)行后面的同步任務(wù)代碼,執(zhí)行完成后,也就是表達(dá)式中的 Promise 解析完成后繼續(xù)執(zhí)行 async 函數(shù)并返回解決結(jié)果。(其實還是本輪循環(huán)promise的問題,最后的resolve屬于異步,位于本輪循環(huán)的末尾。)

  • 問題2:

console.log('promise2')為什么也是在resolve之前執(zhí)行?

解答:注:此內(nèi)容來源與阮一峰老師的ES6書籍,調(diào)用resolve或者reject并不會終結(jié)promise的參數(shù)函數(shù)的執(zhí)行。因為立即resolved的Promise是本輪循環(huán)的末尾執(zhí)行,同時總是晚于本輪循環(huán)的同步任務(wù)。正規(guī)的寫法調(diào)用resolve或者reject以后,Promise的使命就完成了,后繼操作應(yīng)該放在then方法后面。所以最好在它的前面加上return語句,這樣就不會出現(xiàn)意外

new Promise((resolve,reject) => {    return resolve(1);    //后面的語句不會執(zhí)行    console.log(2);}
  • 問題3:

promise3和script end的執(zhí)行順序是否有疑問?

解答:因為立即resolved的Promise是本輪循環(huán)的末尾執(zhí)行,同時總是晚于本輪循環(huán)的同步任務(wù)。Promise 是一個立即執(zhí)行函數(shù),但是他的成功(或失敗:reject)的回調(diào)函數(shù) resolve 卻是一個異步執(zhí)行的回調(diào)。當(dāng)執(zhí)行到 resolve() 時,這個任務(wù)會被放入到回調(diào)隊列中,等待調(diào)用棧有空閑時事件循環(huán)再來取走它。本輪循環(huán)中最后執(zhí)行的。

整體結(jié)論

用一道大廠面試題帶你搞懂事件循環(huán)機制

 

順序的整體總結(jié)就是: 同步任務(wù)-> 本輪循環(huán)->次輪循環(huán)

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多