欧美亚洲中文,在线国自产视频,欧洲一区在线观看视频,亚洲综合中文字幕在线观看

      1. <dfn id="rfwes"></dfn>
          <object id="rfwes"></object>
        1. 站長資訊網(wǎng)
          最全最豐富的資訊網(wǎng)站

          一文帶你了解Node.js中的eventloop

          主線程從"任務(wù)隊(duì)列"中讀取事件,這個(gè)過程是循環(huán)不斷的,所以整個(gè)的這種運(yùn)行機(jī)制又稱為Event Loop(事件循環(huán))。下面本篇文章就來帶大家掌握Node.js中的eventloop,希望對(duì)大家有所幫助!

          一文帶你了解Node.js中的eventloop

          其實(shí)在前面的文章我也講述過瀏覽器中的eventloop。然而在NodeJs中的eventloop與瀏覽器的是有區(qū)別的。對(duì)于寫nodejs的人來說掌握eventloop是一項(xiàng)很重要的技能。因?yàn)檫@意味著你不僅是會(huì)寫js,而對(duì)NodeJs也是有研究的。

          為什么要有eventloop?

          我們知道NodeJs的本質(zhì)是把瀏覽器的v8搬到了操作系統(tǒng)中運(yùn)行,因此也把瀏覽器的事件循環(huán)拿過來了。可是為什么會(huì)出現(xiàn)eventloop這樣的設(shè)計(jì)呢?

          從歷史原因上來看,js在設(shè)計(jì)時(shí)只是一門很簡單的為了在頁面上操作一下dom的語言(相信大家都聽過js只用了10天就設(shè)計(jì)出來的故事)。出于這個(gè)目標(biāo),我們當(dāng)然希望js的運(yùn)行盡可能的簡單,輕量,有多輕呢?輕到j(luò)s的渲染引擎是在一個(gè)線程中運(yùn)行的。

          那么問題來了如果是在一個(gè)線程上運(yùn)行js,當(dāng)代碼是線性的時(shí)候,當(dāng)然是沒有問題的。但在頁面上,我們需要用戶的交互,而這些交互是不知道為什么時(shí)候發(fā)生的。那js要怎么處理?如果眼前有正在運(yùn)行的代碼,一個(gè)用戶交互進(jìn)來之后,程序該怎么反應(yīng)?如果先處理用戶的交互,那原來的程序就會(huì)被暫停(也就是阻塞)。為了避免這種阻塞,js采用了一個(gè)辦法,就是用一個(gè)消息隊(duì)列,來存放這種用戶交互。等所有的程序跑完之后,再去消息隊(duì)列中拿交互事件,然后執(zhí)行。這樣就解決了阻塞的問題了。

          瀏覽器的eventloop

          我們都知道瀏覽器在瀏覽頁面的時(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)文章中講過,為了給不同的異步任務(wù)分類,在事件循環(huán)中其實(shí)是有宏任務(wù)和微任務(wù)的區(qū)分的。他們的執(zhí)行大致為

          向消息隊(duì)列拿微任務(wù)-->執(zhí)行微任務(wù)-->微任務(wù)執(zhí)行完畢--> 向消息隊(duì)列拿宏任務(wù)-->執(zhí)行宏任務(wù)-->宏任務(wù)執(zhí)行完畢-->向消息隊(duì)列拿微任務(wù)-->...

          NodeJs的eventloop

          node的事件循環(huán)其實(shí)大致思路跟在瀏覽器上的是相似的,但nodeJs對(duì)不同的宏任務(wù)又作出了不同時(shí)期的區(qū)分。下面是官方的流程圖:

          一文帶你了解Node.js中的eventloop

          可以看到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)部使用,開發(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í)通過上述表格,我們已經(jīng)很清晰知道整個(gè)事件循環(huán)機(jī)制的執(zhí)行順序了。但可能大家還會(huì)有一些疑問。下面來詳細(xì)講一下。

          pending callbacks

          這個(gè)階段其實(shí)是處理由于操作系統(tǒng)出錯(cuò),導(dǎo)致一些本應(yīng)在上次事件循環(huán)中執(zhí)行的回調(diào)。例如一些TCP錯(cuò)誤。因此這部分,開發(fā)者不能主動(dòng)操作,是NodeJs的一些容錯(cuò)機(jī)制。

          check

          同樣的,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)先處理。

          close callbacks

          這個(gè)時(shí)期處理關(guān)閉事件,如socket.on('close', …) 等這樣可以確保在一些通訊結(jié)束前,所有任務(wù)都完成了。

          微任務(wù)在eventloop中

          我們先來回顧瀏覽器與nodejs的差異:

          宏任務(wù):

          任務(wù) 瀏覽器 Node
          I/O
          setTimeout
          setInterval
          setImmediate
          requestAnimationFrame

          微任務(wù):

          任務(wù) 瀏覽器 Node
          process.nextTick
          MutationObserver
          Promise.then catch finally

          可以看到process.nextTick是nodejs特有的微任務(wù),不僅如此,process.nextTick()的優(yōu)先級(jí)高于所有的微任務(wù),每一次清空微任務(wù)列表的時(shí)候,都是先執(zhí)行 process.nextTick()

          執(zhí)行差異

          不僅是任務(wù)類型上有差異,在執(zhí)行上2個(gè)環(huán)境其實(shí)也有差異。在瀏覽器上執(zhí)行任務(wù)的時(shí)候,每執(zhí)行一個(gè)宏任務(wù)之前,需要先確保微任務(wù)隊(duì)列執(zhí)行完了。而在nodejs上是每個(gè)時(shí)期之前,先確保微任務(wù)隊(duì)列執(zhí)行完。也就是說在假如在timer時(shí)期,會(huì)先把所有setTimeout,setInterval的宏任務(wù)執(zhí)行完。在執(zhí)行完微任務(wù),再進(jìn)入下個(gè)時(shí)期。

          注意:以上執(zhí)行規(guī)則是在nodejs的v11版本之前的規(guī)則。在11版本之后nodejs的執(zhí)行輸出是跟瀏覽器一樣的。

          setImmediate() vs setTimeout()

          setImmediate() 和 setTimeout()的執(zhí)行先后順序是不一定的,就是說如果你不停地執(zhí)行以下代碼,每次得到的結(jié)果可能是不一樣的。

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

          其中的原因是程序?qū)r(shí)間的處理是有誤差的。在setTimeout方法中設(shè)置的時(shí)間,不一定是準(zhǔn)確的。同時(shí)在回調(diào)觸發(fā)時(shí),也無法確認(rèn)事件循環(huán)處在哪個(gè)時(shí)期,可能是timer,也可能是check。所有會(huì)有不同的結(jié)果。

          總結(jié)

          eventloop是js運(yùn)行機(jī)制里的重點(diǎn)內(nèi)容,對(duì)于NodeJs來說,eventloop的操作空間則更大。因?yàn)樗患?xì)分為不同的時(shí)期,從而讓我們可能把邏輯進(jìn)一步細(xì)化。同時(shí)利用nextTick的最高優(yōu)先級(jí),可以寫出在瀏覽器無法實(shí)現(xiàn)的代碼。因此對(duì)于深入NodeJs的開發(fā)者來說,eventloop往往是他們考察新人對(duì)NodeJs理解的第一步。

          贊(0)
          分享到: 更多 (0)
          網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)