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

  • 站長資訊網
    最全最豐富的資訊網站

    圖文結合帶你搞懂Nodejs中的事件循環(huán)

    本篇文章通過圖文結合的形式來帶大家搞懂Nodejs中的事件循環(huán),希望對大家有所幫助!

    圖文結合帶你搞懂Nodejs中的事件循環(huán)

    以下全文7000字,請在你思路清晰、精力充沛的時刻觀看。保證你理解后很長時間忘不掉?!就扑]學習:《nodejs 教程》】

    圖文結合帶你搞懂Nodejs中的事件循環(huán)

    Node事件循環(huán)

    Node底層使用的語言libuv,是一個c++語言。他用來操作底層的操作系統(tǒng),封裝了操作系統(tǒng)的接口。Node的事件循環(huán)也是用libuv來寫的,所以Node生命周期和瀏覽器的還是有區(qū)別的。

    因為Node和操作系統(tǒng)打交道,所以事件循環(huán)比較復雜,也有一些自己特有的API。
    事件循環(huán)在不同的操作系統(tǒng)里有一些細微的差異。這將涉及到操作系統(tǒng)的知識,暫時不表。 本次只介紹JS主線程中,Node的運作流程。Node的其他線程暫時也不擴展。

    事件循環(huán)圖

    說好的一張圖,也不賣關子。下邊這張圖搞清楚了,事件循環(huán)就學會了。

    圖文結合帶你搞懂Nodejs中的事件循環(huán)

    事件循環(huán)圖

    圖文結合帶你搞懂Nodejs中的事件循環(huán)

    事件循環(huán)圖-結構

    為了讓大家先有個大局觀,先貼一張目錄結構圖在前邊:

    圖文結合帶你搞懂Nodejs中的事件循環(huán)

    目錄

    接下來詳細展開說說

    主線程

    圖文結合帶你搞懂Nodejs中的事件循環(huán)

    主線程

    上圖中,幾個色塊的含義:

    • main:啟動入口文件,運行主函數
    • event loop:檢查是否要進入事件循環(huán)
      • 檢查其他線程里是否還有待處理事項
      • 檢查其他任務是否還在進行中(比如計時器、文件讀取操作等任務是否完成)
      • 有以上情況,進入事件循環(huán),運行其他任務
        事件循環(huán)的過程:沿著從timers到close callbacks這個流程,走一圈。到event loop看是否結束,沒結束再走一圈。
    • over:所有的事情都完畢,結束

    事件循環(huán) 圈

    圖文結合帶你搞懂Nodejs中的事件循環(huán)

    事件循環(huán) 圈

    圖中灰色的圈跟操作系統(tǒng)有關系,不是本章解析重點。重點關注黃色、橙色的圈還有中間橘黃的方框。

    我們把每一圈的事件循環(huán)叫做「一次循環(huán)」、又叫「一次輪詢」、又叫「一次Tick」。

    一次循環(huán)要經過六個階段:

    • timers:計時器(setTimeout、setInterval等的回調函數存放在里邊)

    • pending callback

    • idle prepare

    • poll:輪詢隊列(除timers、check之外的回調存放在這里)

    • check:檢查階段(使用 setImmediate 的回調會直接進入這個隊列)

    • close callbacks

    圖文結合帶你搞懂Nodejs中的事件循環(huán)

    本次我們只關注上邊標紅的三個重點。

    工作原理

    • 每一個階段都會維護一個事件隊列。可以把每一個圈想象成一個事件隊列。
    • 這就和瀏覽器不一樣了,瀏覽器最多兩個隊列(宏隊列、微隊列)。但是在node里邊有六個隊列
    • 到達一個隊列后,檢查隊列內是否有任務(也就是看下是否有回調函數)需要執(zhí)行。如果有,就依次執(zhí)行,直到全部執(zhí)行完畢、清空隊列。
    • 如果沒有任務,進入下一個隊列去檢查。直到所有隊列檢查一遍,算一個輪詢。
    • 其中,timers、pending callbackidle prepare等執(zhí)行完畢后,到達poll隊列。

    timers隊列的工作原理

    timers并非真正意義上的隊列,他內部存放的是計時器。
    每次到達這個隊列,會檢查計時器線程內的所有計時器,計時器線程內部多個計時器按照時間順序排序。

    檢查過程:將每一個計時器按順序分別計算一遍,計算該計時器開始計時的時間到當前時間是否滿足計時器的間隔參數設定(比如1000ms,計算計時器開始計時到現(xiàn)在是否有1m)。當某個計時器檢查通過,則執(zhí)行其回調函數。

    poll隊列的運作方式

    • 如果poll中有回調函數需要執(zhí)行,依次執(zhí)行回調,直到清空隊列。
    • 如果poll中沒有回調函數需要執(zhí)行,已經是空隊列了。則會在這里等待,等待其他隊列中出現(xiàn)回調,
      • 如果其他隊列中出現(xiàn)回調,則從poll向下到over,結束該階段,進入下一階段。
      • 如果其他隊列也都沒有回調,則持續(xù)在poll隊列等待,直到任何一個隊列出現(xiàn)回調后再進行工作。(是個小懶蟲的處事方式)

    舉例梳理事件流程

    setTimeout(() => {   console.log('object'); }, 5000) console.log('node');

    以上代碼的事件流程梳理

    • 進入主線程,執(zhí)行setTimeout(),回調函數作為異步任務被放入異步隊列timers隊列中,暫時不執(zhí)行。
    • 繼續(xù)向下,執(zhí)行定時器后邊的console,打印“node”。
    • 判斷是否有事件循環(huán)。是,走一圈輪詢:從timers – pending callback – idle prepare……
    • poll隊列停下循環(huán)并等待。
      • 由于這時候沒到5秒,timers隊列無任務,所以一直在poll隊列卡著,同時輪詢檢查其他隊列是否有任務。
    • 等5秒到達,setTimeout的回調塞到timers內,例行輪詢檢查到timers隊列有任務,則向下走,經過check、close callbacks后到達timers。將timers隊列清空。
    • 繼續(xù)輪詢到poll等待,詢問是否還需要event loop,不需要,則到達over結束。

    要理解這個問題,看下邊的代碼及流程解析:

    setTimeout(function t1() {   console.log('setTimeout'); }, 5000) console.log('node 生命周期');  const http = require('http')  const server = http.createServer(function h1() {   console.log('請求回調'); });  server.listen(8080)

    代碼分析如下:

    • 照舊,先執(zhí)行主線程,打印“node 生命周期”、引入http后創(chuàng)建http服務。
    • 然后event loop檢查是否有異步任務,檢查發(fā)現(xiàn)有定時器任務和請求任務。所以進入事件循環(huán)。
    • 六個隊列都沒任務,則在poll隊列等待。如下圖:

      圖文結合帶你搞懂Nodejs中的事件循環(huán)

    • 過了五秒,timers中有了任務,則流程從poll放行向下,經過check和close callbacks隊列后,到達event loop。
    • event loop檢查是否有異步任務,檢查發(fā)現(xiàn)有定時器任務和請求任務。所以再次進入事件循環(huán)。
    • 到達timers隊列,發(fā)現(xiàn)有回調函數任務,則依次執(zhí)行回調,清空timers隊列(當然這里只有一個5秒到達后的回調,所以直接執(zhí)行完了即可),打印出“setTimeout”。如下圖

      圖文結合帶你搞懂Nodejs中的事件循環(huán)

    • 清空timers隊列后,輪詢繼續(xù)向下到達poll隊列,由于poll隊列現(xiàn)在是空隊列,所以在這里等待。
    • 后來,假設用戶請求發(fā)來了,h1回調函數被放到poll隊列。于是poll中有回調函數需要執(zhí)行,依次執(zhí)行回調,直到清空poll隊列。
    • poll隊列清空,此時poll隊列是空隊列,繼續(xù)等待。

      圖文結合帶你搞懂Nodejs中的事件循環(huán)

    • 由于node線程一直holding在poll隊列,等很長一段時間還是沒有任務來臨時,會自動斷開等待(不自信表現(xiàn)),向下執(zhí)行輪詢流程,經過check、close callbacks后到達event loop
    • 到了event loop后,檢查是否有異步任務,檢查發(fā)現(xiàn)有請求任務。(此時定時器任務已經執(zhí)行完畢,所以沒有了),則繼續(xù)再次進入事件循環(huán)。
    • 到達poll隊列,再次holding……
    • 再等很長時間沒有任務來臨,自動斷開到even loop(再補充一點無任務的循環(huán)情況)
    • 再次回到poll隊列掛起
    • 無限循環(huán)……

    梳理事件循環(huán)流程圖:

    注意:下圖中的“是否有任務”的說法表示“是否有本隊列的任務”。

    圖文結合帶你搞懂Nodejs中的事件循環(huán)

    event loop流程梳理

    再用一個典型的例子驗證下流程:

    const startTime = new Date();  setTimeout(function f1() {   console.log('setTimeout', new Date(), new Date() - startTime); }, 200)  console.log('node 生命周期', startTime);  const fs = require('fs')  fs.readFile('./poll.js', 'utf-8', function fsFunc(err, data) {   const fsTime = new Date()   console.log('fs', fsTime);   while (new Date() - fsTime < 300) {   }   console.log('結束死循環(huán)', new Date()); });

    連續(xù)運行三遍,打印結果如下:

    圖文結合帶你搞懂Nodejs中的事件循環(huán)

    執(zhí)行流程解析:

    • 執(zhí)行全局上下文,打印「node 生命周期 + 時間」

    • 詢問是否有event loop

    • 有,進入timers隊列,檢查沒有計時器(cpu處理速度可以,這時還沒到200ms)

    • 輪詢進入到poll,讀文件還沒讀完(比如此時才用了20ms),因此poll隊列是空的,也沒有任務回調

    • 在poll隊列等待……不斷輪詢看有沒有回調

    • 文件讀完,poll隊列有了fsFunc回調函數,并且被執(zhí)行,輸出「fs + 時間」

    • 在while死循環(huán)那里卡300毫秒,

    • 死循環(huán)卡到200ms的時候,f1回調進入timers隊列。但此時poll隊列很忙,占用了線程,不會向下執(zhí)行。

    • 直到300ms后poll隊列清空,輸出「結束死循環(huán) + 時間」

    • event loop趕緊向下走

    • 再來一輪到timers,執(zhí)行timers隊列里的f1回調。于是看到「setTimeout + 時間」

    • timers隊列清空,回到poll隊列,沒有任務,等待一會。

    • 等待時間夠長后,向下回到event loop。

    • event loop檢查沒有其他異步任務了,結束線程,整個程序over退出。

    check 階段

    檢查階段(使用 setImmediate 的回調會直接進入這個隊列)

    check隊列的實際工作原理

    真正的隊列,里邊扔的就是待執(zhí)行的回調函數的集合。類似[fn,fn]這種形式的。
    每次到達check這個隊列后,立即按順序執(zhí)行回調函數即可【類似于[fn1,fn2].forEach((fn)=>fn())的感覺】

    所以說,setImmediate不是一個計時器的概念。

    如果你去面試,涉及到Node環(huán)節(jié),可能會遇到下邊這個問題:setImmediate和setTimeout(0)誰更快。

    setImmediate() 與 setTimeout(0) 的對比

    • setImmediate的回調是異步的,和setTimeout回調性質一致。
    • setImmediate回調在check隊列,setTimeout回調在timers隊列(概念意義,實際在計時器線程,只是setTimeout在timers隊列做檢查調用而已。詳細看timers的工作原理)。
    • setImmediate函數調用后,回調函數會立即push到check隊列,并在下次eventloop時被執(zhí)行。setTimeout函數調用后,計時器線程增加一個定時器任務,下次eventloop時會在timers階段里檢查判斷定時器任務是否到達時間,到了則執(zhí)行回調函數。
    • 綜上,setImmediate的運算速度比setTimeout(0)的要快,因為setTimeout還需要開計時器線程,并增加計算的開銷。

    二者的效果差不多。但是執(zhí)行順序不定

    觀察以下代碼:

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

    多次反復運行,執(zhí)行效果如下:

    圖文結合帶你搞懂Nodejs中的事件循環(huán)

    順序不定

    可以看到多次運行,兩句console.log打印的順序不定。
    這是因為setTimeout的間隔數最小填1,雖然下邊代碼填了0。但實際計算機執(zhí)行當1ms算。(這里注意和瀏覽器的計時器區(qū)分。在瀏覽器中,setInterval的最小間隔數為10ms,小于10ms則會被設置為10;設備供電狀態(tài)下,間隔最小為16.6ms。)

    以上代碼,主線程運行的時候,setTimeout函數調用,計時器線程增加一個定時器任務。setImmediate函數調用后,其回調函數立即push到check隊列。主線程執(zhí)行完畢。

    eventloop判斷時,發(fā)現(xiàn)timers和check隊列有內容,進入異步輪詢:

    第一種情況:等到了timers里這段時間,可能還沒有1ms的時間,定時器任務間隔時間的條件不成立所以timers里還沒有回調函數。繼續(xù)向下到了check隊列里,這時候setImmediate的回調函數早已等候多時,直接執(zhí)行。而再下次eventloop到達timers隊列,定時器也早已成熟,才會執(zhí)行setTimeout的回調任務。于是順序就是「setImmediate -> setTimeout」。

    第二種情況:但也有可能到了timers階段時,超過了1ms。于是計算定時器條件成立,setTimeout的回調函數被直接執(zhí)行。eventloop再向下到達check隊列執(zhí)行setImmediate的回調。最終順序就是「setTimeout -> setImmediate」了。

    所以,只比較這兩個函數的情況下,二者的執(zhí)行順序最終結果取決于當下計算機的運行環(huán)境以及運行速度。

    二者時間差距的對比代碼

    ------------------setTimeout測試:------------------- let i = 0; console.time('setTimeout'); function test() {   if (i < 1000) {     setTimeout(test, 0)     i++   } else {     console.timeEnd('setTimeout');   } } test();  ------------------setImmediate測試:------------------- let i = 0; console.time('setImmediate'); function test() {   if (i < 1000) {     setImmediate(test)     i++   } else {     console.timeEnd('setImmediate');   } } test();

    運行觀察時間差距:

    圖文結合帶你搞懂Nodejs中的事件循環(huán)

    setTimeout與setImmediate時間差距

    可見setTimeout遠比setImmediate耗時多得多
    這是因為setTimeout不僅有主代碼執(zhí)行的時間消耗。還有在timers隊列里,對于計時器線程中各個定時任務的計算時間。

    結合poll隊列的面試題(考察timers、poll和check的執(zhí)行順序)

    如果你看懂了上邊的事件循環(huán)圖,下邊這道題難不倒你!

    // 說說下邊代碼的執(zhí)行順序,先打印哪個? const fs = require('fs') fs.readFile('./poll.js', () => {   setTimeout(() => console.log('setTimeout'), 0)   setImmediate(() => console.log('setImmediate')) })

    上邊這種代碼邏輯,不管執(zhí)行多少次,肯定都是先執(zhí)行setImmediate。

    圖文結合帶你搞懂Nodejs中的事件循環(huán)

    先執(zhí)行setImmediate

    因為fs各個函數的回調是放在poll隊列的。當程序holding在poll隊列后,出現(xiàn)回調立即執(zhí)行。
    回調內執(zhí)行setTimeout和setImmediate的函數后,check隊列立即增加了回調。
    回調執(zhí)行完畢,輪詢檢查其他隊列有內容,程序結束poll隊列的holding向下執(zhí)行。
    check是poll階段的緊接著的下一個。所以在向下的過程中,先執(zhí)行check階段內的回調,也就是先打印setImmediate。
    到下一輪循環(huán),到達timers隊列,檢查setTimeout計時器符合條件,則定時器回調被執(zhí)行。

    nextTick 與 Promise

    說完宏任務,接下來說下微任務

    • 二者都是「微隊列」,執(zhí)行異步微任務。
    • 二者不是事件循環(huán)的一部分,程序也不會開啟額外的線程去處理相關任務。(理解:promise里發(fā)網絡請求,那是網絡請求開的網絡線程,跟Promise這個微任務沒關系)
    • 微隊列設立的目的就是讓一些任務「馬上」、「立即」優(yōu)先執(zhí)行。
    • nextTick與Promise比較,nextTick的級別更高。

    nextTick表現(xiàn)形式

    process.nextTick(() => {})

    Promise表現(xiàn)形式

    Promise.resolve().then(() => {})

    如何參與事件循環(huán)?

    事件循環(huán)中,每執(zhí)行一個回調前,先按序清空一次nextTick和promise。

    // 先思考下列代碼的執(zhí)行順序 setImmediate(() => {   console.log('setImmediate'); });  process.nextTick(() => {   console.log('nextTick 1');   process.nextTick(() => {     console.log('nextTick 2');   }) })  console.log('global');   Promise.resolve().then(() => {   console.log('promise 1');   process.nextTick(() => {     console.log('nextTick in promise');   }) })

    最終順序:

    • global

    • nextTick 1

    • nextTick 2

    • promise 1

    • nextTick in promise

    • setImmediate

    兩個問題:

    基于上邊的說法,有兩個問題待思考和解決:

    • 每走一個異步宏任務隊列就查一遍nextTick和promise?還是每執(zhí)行完 宏任務隊列里的一個回調函數就查一遍呢?

    • 如果在poll的holding階段,插入一個nextTick或者Promise的回調,會立即停止poll隊列的holding去執(zhí)行回調嗎?

    圖文結合帶你搞懂Nodejs中的事件循環(huán)

    上邊兩個問題,看下邊代碼的說法

    setTimeout(() => {   console.log('setTimeout 100');   setTimeout(() => {     console.log('setTimeout 100 - 0');     process.nextTick(() => {       console.log('nextTick in setTimeout 100 - 0');     })   }, 0)   setImmediate(() => {     console.log('setImmediate in setTimeout 100');     process.nextTick(() => {       console.log('nextTick in setImmediate in setTimeout 100');     })   });   process.nextTick(() => {     console.log('nextTick in setTimeout100');   })   Promise.resolve().then(() => {     console.log('promise in setTimeout100');   }) }, 100)  const fs = require('fs') fs.readFile('./1.poll.js', () => {   console.log('poll 1');   process.nextTick(() => {     console.log('nextTick in poll ======');   }) })  setTimeout(() => {   console.log('setTimeout 0');   process.nextTick(() => {     console.log('nextTick in setTimeout');   }) }, 0)  setTimeout(() => {   console.log('setTimeout 1');   Promise.resolve().then(() => {     console.log('promise in setTimeout1');   })   process.nextTick(() => {     console.log('nextTick in setTimeout1');   }) }, 1)  setImmediate(() => {   console.log('setImmediate');   process.nextTick(() => {     console.log('nextTick in setImmediate');   }) });  process.nextTick(() => {   console.log('nextTick 1');   process.nextTick(() => {     console.log('nextTick 2');   }) })  console.log('global ------');  Promise.resolve().then(() => {   console.log('promise 1');   process.nextTick(() => {     console.log('nextTick in promise');   }) })  /** 執(zhí)行順序如下 global ------ nextTick 1 nextTick 2 promise 1 nextTick in promise setTimeout 0 // 解釋問題1. 沒有上邊的nextTick和promise,setTimeout和setImmediate的順序不一定,有了以后肯定是0先開始。 // 可見,執(zhí)行一個隊列之前,就先檢查并執(zhí)行了nextTick和promise微隊列 nextTick in setTimeout setTimeout 1 nextTick in setTimeout1 promise in setTimeout1 setImmediate nextTick in setImmediate poll 1 nextTick in poll ====== setTimeout 100 nextTick in setTimeout100 promise in setTimeout100 setImmediate in setTimeout 100 nextTick in setImmediate in setTimeout 100 setTimeout 100 - 0 nextTick in setTimeout 100 - 0  */

    以上代碼執(zhí)行多次,順序不變,setTimeout和setImmediate的順序都沒變。

    執(zhí)行順序及具體原因說明如下:

    • global :主線程同步任務,率先執(zhí)行沒毛病

    • nextTick 1:執(zhí)行異步宏任務之前,清空異步微任務,nextTick優(yōu)先級高,先行一步

    • nextTick 2:執(zhí)行完上邊這句代碼,又一個nextTick微任務,立即率先執(zhí)行

    • promise 1:執(zhí)行異步宏任務之前,清空異步微任務,Promise的優(yōu)先級低,所以在nextTick完了以后立即執(zhí)行

    • nextTick in promise:清空Promise隊列的過程中,遇到nextTick微任務,立即執(zhí)行、清空

    • setTimeout 0: 解釋第一個問題. 沒有上邊的nextTick和promise,只有setTimeout和setImmediate時他倆的執(zhí)行順序不一定。有了以后肯定是0先開始??梢姡瑘?zhí)行一個宏隊列之前,就先按順序檢查并執(zhí)行了nextTick和promise微隊列。等微隊列全部執(zhí)行完畢,setTimeout(0)的時機也成熟了,就被執(zhí)行。

    • nextTick in setTimeout:執(zhí)行完上邊這句代碼,又一個nextTick微任務,立即率先執(zhí)行 【這種回調函數里的微任務,我不能確定是緊隨同步任務執(zhí)行的;還是放到微任務隊列,等下一個宏任務執(zhí)行前再清空的他們。但是順序看上去和立即執(zhí)行他們一樣。不過我比較傾向于是后者:先放到微任務隊列等待,下一個宏任務執(zhí)行前清空他們。】

    • setTimeout 1:因為執(zhí)行微任務耗費時間,導致此時timers里判斷兩個0和1的setTimeout計時器已經結束,所以兩個setTimeout回調都已加入隊列并被執(zhí)行

    • nextTick in setTimeout1:執(zhí)行完上邊這句代碼,又一個nextTick微任務,立即率先執(zhí)行 【可能是下一個宏任務前清空微任務】

    • promise in setTimeout1:執(zhí)行完上邊這句代碼,又一個Promise微任務,立即緊隨執(zhí)行 【可能是下一個宏任務前清空微任務】

    • setImmediate:poll隊列回調時機未到,先行向下到check隊列,清空隊列,立即執(zhí)行setImmediate回調

    • nextTick in setImmediate:執(zhí)行完上邊這句代碼,又一個nextTick微任務,立即率先執(zhí)行 【可能是下一個宏任務前清空微任務】

    • poll 1:poll隊列實際成熟,回調觸發(fā),同步任務執(zhí)行。

    • nextTick in poll :執(zhí)行完上邊這句代碼,又一個nextTick微任務,立即率先執(zhí)行 【可能是下一個宏任務前清空微任務】

    • setTimeout 100:定時器任務到達時間,執(zhí)行回調。并在回調里往微任務推入了nextTick、Promise,往宏任務的check里推入了setImmediate的回調。并且也開啟了計時器線程,往timers里增加了下一輪回調的可能。

    • nextTick in setTimeout100:宏任務向下前,率先執(zhí)行定時器回調內新增的微任務-nextTick 【這里就能確定了,是下一個宏任務前清空微任務的流程】

    • promise in setTimeout100:緊接著執(zhí)行定時器回調內新增的微任務-Promise 【清空完nextTick清空Promise的順序】

    • setImmediate in setTimeout 100:這次setImmediate比setTimeout(0)先執(zhí)行的原因是:流程從timers向后走到check隊列,已經有了setImmediate的回調,立即執(zhí)行。

    • nextTick in setImmediate in setTimeout 100:執(zhí)行完上邊這句代碼,又一個nextTick微任務,下一個宏任務前率先清空微任務

    • setTimeout 100 - 0:輪詢又一次回到timers,執(zhí)行100-0的回調。

    • nextTick in setTimeout 100 - 0:執(zhí)行完上邊這句代碼,又一個nextTick微任務,下一個宏任務前率先清空微任務。

    擴展:為什么有了setImmediate還要有nextTick和Promise?

    一開始設計的時候,setImmediate充當了微隊列的作用(雖然他不是)。設計者希望執(zhí)行完poll后立即執(zhí)行setImmediate(當然現(xiàn)在也確實是這么表現(xiàn)的)。所以起的名字叫Immediate,表示立即的意思。 但是后來問題是,poll里可能有N個任務連續(xù)執(zhí)行,在執(zhí)行期間想要執(zhí)行setImmediate是不可能的。因為poll隊列不停,流程不向下執(zhí)行。

    于是出現(xiàn)nextTick,真正的微隊列概念。但此時,immediate的名字被占用了,所以名字叫nextTick(下一瞬間)。事件循環(huán)期間,執(zhí)行任何一個隊列之前,都要檢查他是否被清空。其次是Promise。

    面試題

    最后,檢驗學習成果的面試題來了

    async function async1() {   console.log('async start');   await async2();   console.log('async end'); }  async function async2(){   console.log('async2'); } console.log('script start');  setTimeout(() => {   console.log('setTimeout 0'); }, 0)  setTimeout(() => {   console.log('setTimeout 3'); }, 3)  setImmediate(() => {   console.log('setImmediate'); })  process.nextTick(() => {   console.log('nextTick'); })  async1();  new Promise((res) => {   console.log('promise1');   res();   console.log('promise2'); }).then(() => {   console.log('promise 3'); });  console.log('script end');  // 答案如下 // - // - // - // - // - // - // - // - // - // - // - // -       /** script start async start async2 promise1 promise2 script end  nextTick async end promise 3  // 后邊這仨的運行順序就是驗證你電腦運算速度的時候了。 速度最好(執(zhí)行上邊的同步代碼 + 微任務 + 計時器運算用了不到0ms): setImmediate setTimeout 0 setTimeout 3  速度中等(執(zhí)行上邊的同步代碼 + 微任務 + 計時器運算用了0~3ms以上): setTimeout 0 setImmediate setTimeout 3  速度較差(執(zhí)行上邊的同步代碼 + 微任務 + 計時器運算用了3ms以上): setTimeout 0 setTimeout 3 setImmediate */

    思維腦圖 – Node生命周期核心階段

    圖文結合帶你搞懂Nodejs中的事件循環(huán)

    圖文結合帶你搞懂Nodejs中的事件循環(huán)

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