亚洲最大看欧美片,亚洲图揄拍自拍另类图片,欧美精品v国产精品v呦,日本在线精品视频免费

  • 站長資訊網(wǎng)
    最全最豐富的資訊網(wǎng)站

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

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

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

    其實在前面的文章我也講述過瀏覽器中的eventloop。然而在NodeJs中的eventloop與瀏覽器的是有區(qū)別的。對于寫nodejs的人來說掌握eventloop是一項很重要的技能。因為這意味著你不僅是會寫js,而對NodeJs也是有研究的。

    為什么要有eventloop?

    我們知道NodeJs的本質(zhì)是把瀏覽器的v8搬到了操作系統(tǒng)中運行,因此也把瀏覽器的事件循環(huán)拿過來了??墒菫槭裁磿霈F(xiàn)eventloop這樣的設(shè)計呢?

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

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

    瀏覽器的eventloop

    我們都知道瀏覽器在瀏覽頁面的時候,用戶交互是隨時可能發(fā)生的,為了可以即時響應(yīng)用戶。js是不會關(guān)閉的,他會不停的循環(huán)。大致如下:

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

    當(dāng)然我們在之前的事件循環(huán)文章中講過,為了給不同的異步任務(wù)分類,在事件循環(huán)中其實是有宏任務(wù)和微任務(wù)的區(qū)分的。他們的執(zhí)行大致為

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

    NodeJs的eventloop

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

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

    可以看到nodeJs中每次事件循環(huán)被分成了具體的6個時期,每個時期會用指定的宏任務(wù)。然后在每個時期的宏任務(wù)執(zhí)行之前,會優(yōu)先執(zhí)行完微任務(wù)隊列。

    總覽

    timers 執(zhí)行由setTimeout()setInterval() 觸發(fā)的回調(diào)
    pending callbacks 執(zhí)行延遲到下一個循環(huán)迭代的I / O回調(diào)
    idle, prepare 只在內(nèi)部使用,開發(fā)者可以不關(guān)注
    poll 檢索新的I / O事件;執(zhí)行I / O相關(guān)的回調(diào)(會執(zhí)行幾乎所有的回調(diào),除了 close callbacks 以及 timers 調(diào)度的回調(diào)和 setImmediate() 調(diào)度的回調(diào),在恰當(dāng)?shù)臅r機(jī)將會阻塞在此階段)
    check 執(zhí)行setImmediate()
    close callbacks 比如socket.on('close', …)

    其實通過上述表格,我們已經(jīng)很清晰知道整個事件循環(huán)機(jī)制的執(zhí)行順序了。但可能大家還會有一些疑問。下面來詳細(xì)講一下。

    pending callbacks

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

    check

    同樣的,setImmediate是nodejs特有的api,他可以立即創(chuàng)建一個異步宏任務(wù)。不僅如此,nodejs在事件循環(huán)中還專門設(shè)了一個check時期,在這個時期會專門執(zhí)行setImmediate的回調(diào)。甚至你可以在這個時期中如果不停的產(chǎn)生setImmediate回調(diào),eventloop會優(yōu)先處理。

    close callbacks

    這個時期處理關(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)先級高于所有的微任務(wù),每一次清空微任務(wù)列表的時候,都是先執(zhí)行 process.nextTick()

    執(zhí)行差異

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

    注意:以上執(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間的處理是有誤差的。在setTimeout方法中設(shè)置的時間,不一定是準(zhǔn)確的。同時在回調(diào)觸發(fā)時,也無法確認(rèn)事件循環(huán)處在哪個時期,可能是timer,也可能是check。所有會有不同的結(jié)果。

    總結(jié)

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

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