這篇文章主要講解了“Node.js中的eventloop怎么用”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“Node.js中的eventloop怎么用”吧!
鳳凰ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場(chǎng)景,ssl證書未來(lái)市場(chǎng)廣闊!成為成都創(chuàng)新互聯(lián)公司的ssl證書銷售渠道,可以享受市場(chǎng)價(jià)格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:13518219792(備注:SSL證書合作)期待與您的合作!
主線程從"任務(wù)隊(duì)列"中讀取事件,這個(gè)過(guò)程是循環(huán)不斷的,所以整個(gè)的這種運(yùn)行機(jī)制又稱為Event Loop(事件循環(huán))。
其實(shí)在前面的文章我也講述過(guò)瀏覽器中的eventloop。然而在NodeJs中的eventloop與瀏覽器的是有區(qū)別的。對(duì)于寫nodejs的人來(lái)說(shuō)掌握eventloop是一項(xiàng)很重要的技能。因?yàn)檫@意味著你不僅是會(huì)寫js,而對(duì)NodeJs也是有研究的。
我們知道NodeJs的本質(zhì)是把瀏覽器的v8搬到了操作系統(tǒng)中運(yùn)行,因此也把瀏覽器的事件循環(huán)拿過(guò)來(lái)了。可是為什么會(huì)出現(xiàn)eventloop這樣的設(shè)計(jì)呢?
從歷史原因上來(lái)看,js在設(shè)計(jì)時(shí)只是一門很簡(jiǎn)單的為了在頁(yè)面上操作一下dom的語(yǔ)言(相信大家都聽(tīng)過(guò)js只用了10天就設(shè)計(jì)出來(lái)的故事)。出于這個(gè)目標(biāo),我們當(dāng)然希望js的運(yùn)行盡可能的簡(jiǎn)單,輕量,有多輕呢?輕到j(luò)s的渲染引擎是在一個(gè)線程中運(yùn)行的。
那么問(wèn)題來(lái)了如果是在一個(gè)線程上運(yùn)行js,當(dāng)代碼是線性的時(shí)候,當(dāng)然是沒(méi)有問(wèn)題的。但在頁(yè)面上,我們需要用戶的交互,而這些交互是不知道為什么時(shí)候發(fā)生的。那js要怎么處理?如果眼前有正在運(yùn)行的代碼,一個(gè)用戶交互進(jìn)來(lái)之后,程序該怎么反應(yīng)?如果先處理用戶的交互,那原來(lái)的程序就會(huì)被暫停(也就是阻塞)。為了避免這種阻塞,js采用了一個(gè)辦法,就是用一個(gè)消息隊(duì)列,來(lái)存放這種用戶交互。等所有的程序跑完之后,再去消息隊(duì)列中拿交互事件,然后執(zhí)行。這樣就解決了阻塞的問(wèn)題了。
我們都知道瀏覽器在瀏覽頁(yè)面的時(shí)候,用戶交互是隨時(shí)可能發(fā)生的,為了可以即時(shí)響應(yīng)用戶。js是不會(huì)關(guān)閉的,他會(huì)不停的循環(huán)。大致如下:
向消息隊(duì)列拿任務(wù)-->執(zhí)行任務(wù)-->執(zhí)行完畢--> 向消息隊(duì)列拿任務(wù)--> ....
當(dāng)然我們?cè)谥暗氖录h(huán)文章中講過(guò),為了給不同的異步任務(wù)分類,在事件循環(huán)中其實(shí)是有宏任務(wù)和微任務(wù)的區(qū)分的。他們的執(zhí)行大致為
向消息隊(duì)列拿微任務(wù)-->執(zhí)行微任務(wù)-->微任務(wù)執(zhí)行完畢--> 向消息隊(duì)列拿宏任務(wù)-->執(zhí)行宏任務(wù)-->宏任務(wù)執(zhí)行完畢-->向消息隊(duì)列拿微任務(wù)-->...
node的事件循環(huán)其實(shí)大致思路跟在瀏覽器上的是相似的,但nodeJs對(duì)不同的宏任務(wù)又作出了不同時(shí)期的區(qū)分。下面是官方的流程圖:
可以看到nodeJs中每次事件循環(huán)被分成了具體的6個(gè)時(shí)期,每個(gè)時(shí)期會(huì)用指定的宏任務(wù)。然后在每個(gè)時(shí)期的宏任務(wù)執(zhí)行之前,會(huì)優(yōu)先執(zhí)行完微任務(wù)隊(duì)列。
timers | 執(zhí)行由setTimeout()和 setInterval()觸發(fā)的回調(diào) |
---|---|
pending callbacks | 執(zhí)行延遲到下一個(gè)循環(huán)迭代的I / O回調(diào) |
idle, prepare | 只在內(nèi)部使用,開(kāi)發(fā)者可以不關(guān)注 |
poll | 檢索新的I / O事件;執(zhí)行I / O相關(guān)的回調(diào)(會(huì)執(zhí)行幾乎所有的回調(diào),除了 close callbacks 以及 timers 調(diào)度的回調(diào)和 setImmediate() 調(diào)度的回調(diào),在恰當(dāng)?shù)臅r(shí)機(jī)將會(huì)阻塞在此階段) |
check | 執(zhí)行setImmediate() |
close callbacks | 比如socket.on('close', ...) |
其實(shí)通過(guò)上述表格,我們已經(jīng)很清晰知道整個(gè)事件循環(huán)機(jī)制的執(zhí)行順序了。但可能大家還會(huì)有一些疑問(wèn)。下面來(lái)詳細(xì)講一下。
這個(gè)階段其實(shí)是處理由于操作系統(tǒng)出錯(cuò),導(dǎo)致一些本應(yīng)在上次事件循環(huán)中執(zhí)行的回調(diào)。例如一些TCP錯(cuò)誤。因此這部分,開(kāi)發(fā)者不能主動(dòng)操作,是NodeJs的一些容錯(cuò)機(jī)制。
同樣的,setImmediate是nodejs特有的api,他可以立即創(chuàng)建一個(gè)異步宏任務(wù)。不僅如此,nodejs在事件循環(huán)中還專門設(shè)了一個(gè)check時(shí)期,在這個(gè)時(shí)期會(huì)專門執(zhí)行setImmediate的回調(diào)。甚至你可以在這個(gè)時(shí)期中如果不停的產(chǎn)生setImmediate回調(diào),eventloop會(huì)優(yōu)先處理。
這個(gè)時(shí)期處理關(guān)閉事件,如socket.on('close', ...)等這樣可以確保在一些通訊結(jié)束前,所有任務(wù)都完成了。
我們先來(lái)回顧瀏覽器與nodejs的差異:
任務(wù) | 瀏覽器 | Node |
---|---|---|
I/O | ? | ? |
setTimeout | ? | ? |
setInterval | ? | ? |
setImmediate | ? | ? |
requestAnimationFrame | ? | ? |
任務(wù) | 瀏覽器 | Node |
---|---|---|
process.nextTick | ? | ? |
MutationObserver | ? | ? |
Promise.then catch finally | ? | ? |
可以看到process.nextTick是nodejs特有的微任務(wù),不僅如此,process.nextTick()的優(yōu)先級(jí)高于所有的微任務(wù),每一次清空微任務(wù)列表的時(shí)候,都是先執(zhí)行 process.nextTick()
不僅是任務(wù)類型上有差異,在執(zhí)行上2個(gè)環(huán)境其實(shí)也有差異。在瀏覽器上執(zhí)行任務(wù)的時(shí)候,每執(zhí)行一個(gè)宏任務(wù)之前,需要先確保微任務(wù)隊(duì)列執(zhí)行完了。而在nodejs上是每個(gè)時(shí)期之前,先確保微任務(wù)隊(duì)列執(zhí)行完。也就是說(shuō)在假如在timer時(shí)期,會(huì)先把所有setTimeout,setInterval的宏任務(wù)執(zhí)行完。在執(zhí)行完微任務(wù),再進(jìn)入下個(gè)時(shí)期。
注意:以上執(zhí)行規(guī)則是在nodejs的v11版本之前的規(guī)則。在11版本之后nodejs的執(zhí)行輸出是跟瀏覽器一樣的。
setImmediate() 和 setTimeout()的執(zhí)行先后順序是不一定的,就是說(shuō)如果你不停地執(zhí)行以下代碼,每次得到的結(jié)果可能是不一樣的。
setTimeout(() => { console.log('timeout'); }, 0); setImmediate(() => { console.log('immediate'); });
其中的原因是程序?qū)r(shí)間的處理是有誤差的。在setTimeout方法中設(shè)置的時(shí)間,不一定是準(zhǔn)確的。同時(shí)在回調(diào)觸發(fā)時(shí),也無(wú)法確認(rèn)事件循環(huán)處在哪個(gè)時(shí)期,可能是timer,也可能是check。所有會(huì)有不同的結(jié)果。
感謝各位的閱讀,以上就是“Node.js中的eventloop怎么用”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)Node.js中的eventloop怎么用這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!
文章名稱:Node.js中的eventloop怎么用
鏈接地址:http://aaarwkj.com/article44/gpjcee.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)頁(yè)設(shè)計(jì)公司、微信公眾號(hào)、標(biāo)簽優(yōu)化、App設(shè)計(jì)、網(wǎng)站排名、服務(wù)器托管
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)