成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專(zhuān)欄INFORMATION COLUMN

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

ShowerSun / 1529人閱讀

本文涵蓋

面試題的引入

對(duì)事件循環(huán)面試題執(zhí)行順序的一些疑問(wèn)

通過(guò)面試題對(duì)微任務(wù)、事件循環(huán)、定時(shí)器等對(duì)深入理解

結(jié)論總結(jié)

面試題

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

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 start
async1 start
async2
promise1
promise2
script end
nextTick
async1 end
promise3
setTimeout0
setImmediate
setTimeout3
提出問(wèn)題

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

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

Node 的異步語(yǔ)法比瀏覽器更復(fù)雜,因?yàn)樗梢愿鷥?nèi)核對(duì)話,不得不搞了一個(gè)專(zhuān)門(mén)的庫(kù) libuv 做這件事。這個(gè)庫(kù)負(fù)責(zé)各種回調(diào)函數(shù)的執(zhí)行時(shí)間,異步任務(wù)最后基于事件循環(huán)機(jī)制還是要回到主線程,一個(gè)個(gè)排隊(duì)執(zhí)行。

詳細(xì)講解 1.本輪循環(huán)與次輪循環(huán)

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

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

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

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

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

2.process.nextTick()

1)process.nextTick不要因?yàn)橛衝ext就被好多小伙伴當(dāng)作次輪循環(huán)。

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

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

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

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

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

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

微任務(wù)隊(duì)列追加在process.nextTick隊(duì)列的后面,也屬于本輪循環(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

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

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

事件循環(huán)最階段最詳細(xì)的講解(官網(wǎng):https://nodejs.org/en/docs/gu...)

timers階段

次階段包括setTimeout()和setInterval()

IO callbacks

大部分的回調(diào)事件,普通的caollback

poll階段

網(wǎng)絡(luò)連接,數(shù)據(jù)獲取,讀取文件等操作

check階段

setImmediate()在這里調(diào)用回調(diào)

close階段
一些關(guān)閉回調(diào),例如socket.on("close", ...)

事件循環(huán)注意點(diǎn)

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

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

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

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

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

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

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

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

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

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

實(shí)際執(zhí)行的時(shí)候,進(jìn)入事件循環(huán)以后,有可能到了1毫秒,也可能還沒(méi)到1毫秒,取決于系統(tǒng)當(dāng)時(shí)的狀況。如果沒(méi)到1毫秒,那么 timers 階段就會(huì)跳過(guò),進(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));
});

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

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

問(wèn)題1:

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

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

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

問(wèn)題2:

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

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

new Promise((resolve,reject) => {
    return resolve(1);
    //后面的語(yǔ)句不會(huì)執(zhí)行
    console.log(2);
}

問(wèn)題3:

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

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

整體結(jié)論

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

附件:參考資料

node.js官網(wǎng):

事件循環(huán):https://nodejs.org/en/docs/gu...

Timers:https://nodejs.org/dist/lates...

加入我們一起學(xué)習(xí)吧!


node學(xué)習(xí)交流群

交流群滿100人不能自動(dòng)進(jìn)群, 請(qǐng)?zhí)砑尤褐治⑿盘?hào):【coder_qi】備注node,自動(dòng)拉你入群。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/106894.html

相關(guān)文章

  • 【Python從入門(mén)到實(shí)戰(zhàn)】一篇文章帶搞懂Python中的類(lèi)~

    摘要:小栗子對(duì)于可樂(lè)來(lái)講,只要是同一個(gè)品牌的可樂(lè),他們就有著同樣的成分,這被稱之為配方。小栗子對(duì)于可樂(lè)來(lái)說(shuō),按照配方把可樂(lè)生產(chǎn)出來(lái)的過(guò)程就是實(shí)例化的過(guò)程。小栗子類(lèi)的屬性與正常的變量并無(wú)區(qū)別。 前言 我是栗子,帶大家從零開(kāi)始學(xué)習(xí)Python,希望每篇文章都能讓你收獲滿滿! 今天我們要說(shuō)的是面向?qū)ο蟮?..

    cloud 評(píng)論0 收藏0
  • 以??簡(jiǎn)單易懂??的語(yǔ)言帶搞懂有監(jiān)督學(xué)習(xí)算法【附Python代碼詳解】機(jī)器學(xué)習(xí)系列之KNN篇

    必須要看的前言 本文風(fēng)格:以??簡(jiǎn)單易懂??的語(yǔ)言帶你徹底搞懂KNN,了解什么是有監(jiān)督學(xué)習(xí)算法。 認(rèn)真看完這篇文章,徹底了解KNN、了解監(jiān)督學(xué)習(xí)算法絕對(duì)是一樣很簡(jiǎn)單的事情。 注:本篇文章非常詳細(xì),同時(shí)我也附加了Python代碼,歡迎收藏后慢慢閱讀。 目錄 必須要看的前言監(jiān)督學(xué)習(xí)算法KNN/K近鄰算法1 算法原理1.1 實(shí)現(xiàn)過(guò)程1.2 距離的確定 2 算法的優(yōu)缺點(diǎn)3 算法的變種3.1 變...

    MoAir 評(píng)論0 收藏0
  • 優(yōu)秀文章收藏(慢慢消化)持續(xù)更新~

    摘要:整理收藏一些優(yōu)秀的文章及大佬博客留著慢慢學(xué)習(xí)原文協(xié)作規(guī)范中文技術(shù)文檔協(xié)作規(guī)范阮一峰編程風(fēng)格凹凸實(shí)驗(yàn)室前端代碼規(guī)范風(fēng)格指南這一次,徹底弄懂執(zhí)行機(jī)制一次弄懂徹底解決此類(lèi)面試問(wèn)題瀏覽器與的事件循環(huán)有何區(qū)別筆試題事件循環(huán)機(jī)制異步編程理解的異步 better-learning 整理收藏一些優(yōu)秀的文章及大佬博客留著慢慢學(xué)習(xí) 原文:https://www.ahwgs.cn/youxiuwenzhan...

    JeOam 評(píng)論0 收藏0
  • EventBus框架庫(kù)代碼走讀,帶你全面理解View的繪制流程

    摘要:如果當(dāng)前不是主線程則直接調(diào)用,如果是線程則創(chuàng)建一個(gè)加入到后臺(tái)的一個(gè)隊(duì)列,最終由中的一個(gè)線程池去調(diào)用。拋出線程狀態(tài)非法異常。 while (clazz != null) {String name = clazz.getName();if (name.startsWith(java.) || name.starts...

    番茄西紅柿 評(píng)論0 收藏2637
  • 前端 100 問(wèn):能搞懂80%的請(qǐng)把簡(jiǎn)歷給我

    摘要:解析第題第題為什么的和的中不能做異步操作解析第題第題京東下面代碼中在什么情況下會(huì)打印解析第題第題介紹下及其應(yīng)用。盡量減少操作次數(shù)。解析第題第題京東快手周一算法題之兩數(shù)之和給定一個(gè)整數(shù)數(shù)組和一個(gè)目標(biāo)值,找出數(shù)組中和為目標(biāo)值的兩個(gè)數(shù)。 引言 半年時(shí)間,幾千人參與,精選大廠前端面試高頻 100 題,這就是「壹題」。 在 2019 年 1 月 21 日這天,「壹題」項(xiàng)目正式開(kāi)始,在這之后每個(gè)工...

    Scott 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<