目錄
libuv
問題
nodeJs 中的event-loop
timers
poll
check
小总结
案例
了解下浏览器和node的event-loop差异在什么地方
关于 process.nextTick()和setImmediate
process.nextTick()
event-loop核心思维导图
结束语
首頁 web前端 js教程 一文聊聊Node.js中的event-loop機制

一文聊聊Node.js中的event-loop機制

Nov 05, 2021 am 09:48 AM
node.js

本篇文章帶大家一起來了解Node.js中的event-loop(時間循環)機制,希望對大家有幫助!

一文聊聊Node.js中的event-loop機制

今天我們來學習下nodeJs中的event-loop。 event-loop的理解對我來說一直都是一個比較大的難點,希望透過這次的學習把這個難點突破,也希望能透過這篇部落格加深自己對event-loop的理解和印象。

libuv

在學習event-loop之前,先了解下node的libuv。 libuv負責不同作業系統上的不同I/O模型的實現,並且把不同的實作抽象化為能應用與第三方應用程式的API。

一文聊聊Node.js中的event-loop機制

問題

在正式學習event-loop前,先思考一個問題

    setTimeout(() => {
      console.log("timer1");
      Promise.resolve().then(() => {
        console.log("promise1");
      });
    }, 0);

    setTimeout(() => {
      console.log("timer2");
      Promise.resolve().then(() => {
        console.log("promise2");
      });
    }, 0);
登入後複製

這段程式碼在瀏覽器中運行的結果是怎樣的?

一文聊聊Node.js中的event-loop機制

在node中運行的結果又是怎麼樣的呢?

在node8.6之前:

一文聊聊Node.js中的event-loop機制

#node8.6之後:

一文聊聊Node.js中的event-loop機制

為什麼會有這樣的結果,我們稍後會分析!

nodeJs 中的event-loop

首先,來看一張圖:

一文聊聊Node.js中的event-loop機制

在圖中可以看到6個階段,分別是:timers,pending callbacks,idle/prepare,poll,check,close callbacks。

  • timers階段:主要執行setTimeOut,setInterval的回呼

  • pending callbacks階段:執行一些系統呼叫的錯誤,比如說網路通訊的錯誤回呼

  • idle/prepare階段:只在系統內部使用(這個階段我們控制干涉不了)

  • poll階段:取得新的I/O事件,例如取得一個讀取檔案的I/O回呼。 在適合的情況下,nodejs將阻塞在這個階段

  • check階段:執行setImmediate的回呼

  • 例如執行sokect的destory,close事件回呼

每一個階段都遵循一個FIFO(先入先出)的規則來執行任務佇列裡面的任務。 在這六個階段中,我們著重需要關注的是timers,poll,check階段。我們日常開發中絕大部分的非同步任務都是在這三個階段處理的。

timers

我們先來談談timers階段。
timers是事件循環的第一個階段,nodejs會去檢查有沒有已經過期了的timer,如果有,就將它的回調放入佇列中。但是nodejs並不能保證timer在預設事件到了就會立即執行回調,這是因為nodejs對timer的過期檢查不一定可靠,它會受機器上其他運行程序的影響,或者是會遇到當前主線程不空閒的情況。
對於這裡的不確定性,官網上舉了一個例子:
先聲明一個setTimeOut,然後外部讀取一個文件,當讀取文件操作超過定時器的時間,這樣一來讀檔案操作就會把定時器的回調延後,這就是前面說的主執行緒不空閒的情況。

poll

poll階段主要是執行兩件事:

1、處理poll階段的任務佇列 

2、當有了已經逾時的timer執行它的回呼函數

一文聊聊Node.js中的event-loop機制

在上圖中,我們還可以看到:在poll階段執行完poll任務佇列的任務之後,會去檢查有無預設的setImmediate,如果有,則進入check階段,如果沒有,則nodejs將會阻塞在這裡。

這裡我們就會有一個疑問了,如果阻塞在poll階段,那我們設定的timer豈不是執行不了了嗎?
其實當event-loop阻塞在poll階段時,nodejs會有一個檢查機制,它會去檢查timers佇列是否為空,如果不為空,則重新進入timers階段。

check

check階段主要時執行setImmediate的回呼函數。

小总结

event-loop的每个阶段都有一个队列,当event-loop达到某个阶段之后,将执行这个阶段的任务队列,直到队列清空或者达到系统规定的最大回调限制之后,才会进入下一个阶段。当所有阶段都执行完成一次之后,称event-loop完成一个tick。

案例

上面我们说完了event-loop的理论部分,但是光有理论我们也还是不能很清晰的理解event-loop。下面我们就根据几个demo来更加深入的理解下event-loop!

demo1

    const fs=require('fs')
    fs.readFile('test.txt',()=>{
            console.log('readFile')
            setTimeout(()=>{
                    console.log('settimeout');
            },0)
            setImmediate(()=>{
                    console.log('setImmediate')
            })
    })
登入後複製

执行结果:

一文聊聊Node.js中的event-loop機制

可见执行结果跟我们前面的分析时一致的!

demo2

    const fs = require("fs");
    const EventEmitter = require("events").EventEmitter;
    let pos = 0;
    const messenger = new EventEmitter();

    messenger.on("message", function (msg) {
      console.log(++pos + " message:" + msg); //
    });

    console.log(++pos + " first"); //

    process.nextTick(function () {
      console.log(++pos + " nextTick"); //
    });

    messenger.emit("message", "hello!");
    fs.stat(__filename, function () {
      console.log(++pos + " stat"); //
    });

    setTimeout(function () {
      console.log(++pos + " quick timer"); //
    }, 0);
    setTimeout(function () {
      console.log(++pos + " long timer"); //
    }, 30);
    setImmediate(function () {
      console.log(++pos + " immediate"); //
    });

    console.log(++pos + " last"); //
登入後複製

结果:

一文聊聊Node.js中的event-loop機制

了解下浏览器和node的event-loop差异在什么地方

在node 8.6 之前:

浏览器中的微任务队列会在每个宏任务执行完成之后执行,而node中的微任务会在事件循环的各个阶段之间执行,即每个阶段执行完成之后会去执行微任务队列。

在8.6之后:

浏览器和node中微任务的执行是一致的!

所以,在文章开头,我们提出的思考的问题就有了结果。

关于 process.nextTick()和setImmediate

process.nextTick()

语法:process.nextTick(callback,agrs)

执行时机:

这个函数其实是独立于 Event Loop 之外的,它有一个自己的队列,当每个阶段完成后,如果存在 nextTick 队列,就会清空队列中的所有回调函数,并且优先于其他 microtask 执行。递归的调用process.nextTick()会导致I/O starving,官方推荐使用setImmediate()

关于starving现象的说明:

    const fs = require("fs");
    fs.readFile("test.txt", (err, msg) => {
      console.log("readFile");
    });

    let index = 0;

    function handler() {
      if (index >= 30) return;
      index++;
      console.log("nextTick" + index);
      process.nextTick(handler);
    }

    handler();
登入後複製

运行结果:

一文聊聊Node.js中的event-loop機制

可以看到,等到nextTick函数呗执行30次之后,读取文件的回调才被执行!这样的现象被称为 I/O 饥饿

当我们把 process.nextTick 换为 setImmediate

    const fs = require("fs");
    fs.readFile("test.txt", (err, msg) => {
      console.log("readFile");
    });

    let index = 0;

    function handler() {
      if (index >= 30) return;
      index++;
      console.log("nextTick" + index);
      setImmediate(handler);
    }

    handler();
登入後複製

结果:

一文聊聊Node.js中的event-loop機制

造成这两种差异的原因是,嵌套调用的setImmediate的回调被排到了下一次event-loop中去!

event-loop核心思维导图

1一文聊聊Node.js中的event-loop機制

结束语

通过今天的学习,让我对event-loop的理解更深刻了。那么,下次见。好好学习,天天向上!

1一文聊聊Node.js中的event-loop機制

更多编程相关知识,请访问:编程视频!!

以上是一文聊聊Node.js中的event-loop機制的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
4 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

一文聊聊Node中的記憶體控制 一文聊聊Node中的記憶體控制 Apr 26, 2023 pm 05:37 PM

基於無阻塞、事件驅動建立的Node服務,具有記憶體消耗低的優點,非常適合處理海量的網路請求。在海量請求的前提下,就需要考慮「記憶體控制」的相關問題了。 1. V8的垃圾回收機制與記憶體限制 Js由垃圾回收機

圖文詳解Node V8引擎的記憶體和GC 圖文詳解Node V8引擎的記憶體和GC Mar 29, 2023 pm 06:02 PM

這篇文章帶大家深入了解NodeJS V8引擎的記憶體和垃圾回收器(GC),希望對大家有幫助!

深入聊聊Node中的File模組 深入聊聊Node中的File模組 Apr 24, 2023 pm 05:49 PM

文件模組是對底層文件操作的封裝,例如文件讀寫/打開關閉/刪除添加等等文件模組最大的特點就是所有的方法都提供的**同步**和**異步**兩個版本,具有sync 字尾的方法都是同步方法,沒有的都是異

聊聊如何選擇一個最好的Node.js Docker映像? 聊聊如何選擇一個最好的Node.js Docker映像? Dec 13, 2022 pm 08:00 PM

選擇一個Node的Docker映像看起來像是小事,但是映像的大小和潛在漏洞可能會對你的CI/CD流程和安全造成重大的影響。那我們要如何選擇一個最好Node.js Docker映像呢?

Node.js 19正式發布,聊聊它的 6 大功能! Node.js 19正式發布,聊聊它的 6 大功能! Nov 16, 2022 pm 08:34 PM

Node 19已正式發布,以下這篇文章就來帶大家詳解了解Node.js 19的 6 大特性,希望對大家有幫助!

聊聊Node.js中的 GC (垃圾回收)機制 聊聊Node.js中的 GC (垃圾回收)機制 Nov 29, 2022 pm 08:44 PM

Node.js 是如何做 GC (垃圾回收)的?下面這篇文章就來帶大家了解一下。

一起聊聊Node中的事件循環 一起聊聊Node中的事件循環 Apr 11, 2023 pm 07:08 PM

事件循環是 Node.js 的基本組成部分,透過確保主執行緒不被阻塞來實現非同步編程,了解事件循環對建立高效應用程式至關重要。以下這篇文章就來帶大家深入了解Node中的事件循環 ,希望對大家有幫助!

node無法用npm指令怎麼辦 node無法用npm指令怎麼辦 Feb 08, 2023 am 10:09 AM

node無法用npm指令是因為沒有正確配置環境變量,其解決方法是:1、開啟“系統屬性”;2、找到“環境變數”->“系統變數”,然後編輯環境變數;3、找到nodejs所在的資料夾;4、點選「確定」即可。

See all articles