搜尋
首頁web前端js教程深入淺析Node事件循環中的微任務佇列

深入淺析Node事件循環中的微任務佇列

Apr 13, 2023 pm 05:39 PM
javascript前端node.js

深入淺析Node事件循環中的微任務佇列

之前的文章 中,我們了解到事件循環是 Node.js 的關鍵部分,用於協調同步和非同步程式碼的執行。

它由六個不同的隊列組成。一個 nextTick 佇列和一個 Promise 佇列(被稱為微任務佇列)、一個計時器佇列、一個 I/O 佇列、一個檢查佇列,最後是關閉佇列。 【相關教學推薦:nodejs影片教學程式教學

#在每次循環中,回呼函數會在適當時出隊(dequeued)並在調用棧上執行。從本文開始,我們會進行一些實驗以確保我們對事件循環的理解是正確的。

我們的第一組實驗,將重點放在 nextTick 隊列 和 Promise 隊列。但在深入實驗之前,需要先了解如何將回呼函數排到隊列中。

注意:所有實驗都是使用 CommonJS 模組格式進行的。

入隊回呼函數

要將回呼函數加入 nextTick 佇列中,我們可以使用內建的 process.nextTick() 方法。語法很簡單:process.nextTick(callbackFn)。當方法在呼叫堆疊上執行時,回呼函數將被加入到 nextTick 佇列中。

要將回呼函數加入 Promise 佇列中,我們需要使用 Promise.resolve().then(callbackFn)。當 Promise 解決時(resolve),傳遞給 then() 的回呼函數將會被入隊到 Promise 佇列中。

現在我們已經了解如何在兩個佇列中加入回呼函數,讓我們開始第一個實驗吧。

實驗一

程式碼

// index.js
console.log("console.log 1");
process.nextTick(() => console.log("this is process.nextTick 1"));
console.log("console.log 2");

這段程式碼,記錄了三個不同的語句。第二個語句使用 process.nextTick() 將回呼函數排入 nextTick 佇列。

視覺化

深入淺析Node事件循環中的微任務佇列

第一個console.log() 語句被推入呼叫堆疊中執行。它在控制台中記錄相應的訊息,然後彈出堆疊。

接下來,在呼叫堆疊上執行 process.nextTick(),將回呼函數入隊到 nextTick 佇列,並彈出。此時仍有使用者編寫的程式碼需要執行,因此回呼函數必須等待其輪到。

執行繼續進行,最後一個 console.log() 語句被推入堆疊中,該訊息記錄在控制台中,並將該函數從呼叫堆疊中彈出。現在,沒有更多的使用者編寫同步程式碼需要執行,因此控制權進入事件循環。

nextTick 佇列中的回呼函數被推入呼叫棧,console.log() 被推入呼叫堆疊並且執行,在控制台記錄對應的訊息。

console.log 1
console.log 2
this is process.nextTick 1

推論

所有使用者所寫的同步 JavaScript 程式碼優先於非同步程式碼執行。

讓我們繼續進行第二個實驗。

實驗二

程式碼

// index.js
Promise.resolve().then(() => console.log("this is Promise.resolve 1"));
process.nextTick(() => console.log("this is process.nextTick 1"));

我們有一個 Promise.resolve().then() 呼叫和一個 process.nextTick() 呼叫。

視覺化

assets_YJIGb4i01jvw0SRdL5Bt_b32c606155c14ecfa60c8dc102f3bcf0_compressed (1).gif

當呼叫堆疊執行第1 行時,它將回調函數排隊到Promise 佇列中;當呼叫棧執行第2 行時,它將回呼函數排隊到nextTick 佇列中。

第 2 行後沒有程式碼需要執行。

控制權進入事件循環,在其中 nextTick 佇列優先於 Promise 佇列(這是 Node.js 運行時的工作方式)。

事件循環執行 nextTick 佇列回呼函數,然後再執行 Promise 佇列回呼函數。

控制台顯示“this is process.nextTick 1”,然後是“this is Promise.resolve 1”。

this is process.nextTick 1
this is Promise.resolve 1

推論

nextTick 佇列中的所有回呼函數優先於 Promise 佇列中的回呼函數執行。

讓我帶你走一遍上述第二個實驗的更詳細版本。

福利實驗

#
// index.js
process.nextTick(() => console.log("this is process.nextTick 1"));
process.nextTick(() => {
  console.log("this is process.nextTick 2");
  process.nextTick(() =>
    console.log("this is the inner next tick inside next tick")
  );
});
process.nextTick(() => console.log("this is process.nextTick 3"));

Promise.resolve().then(() => console.log("this is Promise.resolve 1"));
Promise.resolve().then(() => {
  console.log("this is Promise.resolve 2");
  process.nextTick(() =>
    console.log("this is the inner next tick inside Promise then block")
  );
});
Promise.resolve().then(() => console.log("this is Promise.resolve 3"));

此程式碼包含三個process.nextTick()呼叫和三個Promise.resolve() 呼叫語句。每個回調函數記錄適當的訊息。

但是,第二个 process.nextTick() 和第二个 Promise.resolve() 都有一个额外的 process.nextTick() 语句,每个都带有一个回调函数。

可视化

assets_YJIGb4i01jvw0SRdL5Bt_b32c606155c14ecfa60c8dc102f3bcf0_compressed (2).gif

为了加快对此可视化的解释,我将省略调用栈讲解。当调用栈执行所有 6 个语句时,nextTick 队列中有 3 个回调函数,Promise 队列中也有 3 个回调函数。没有其他要执行的内容后,控制权进入事件循环。

我们知道,nextTick 队列中具有高优先级。首先执行第 1 个回调函数,并将相应的消息记录到控制台中。

接下来,执行第 2 个回调函数,记录了第 2 条日志语句。但是,这个回调函数包含另一个对 process.nextTick() 的调用,该方法内的回调函数(译注:即() => console.log("this is the inner next tick inside next tick"))入队到nextTick 队列末尾。

然后 Node.js 执行第 3 个回调函数并将相应消息记录到控制台上。最初只有 3 个回调,但是因为第 2 次时向nextTick 队列又添加了一个,所以变成 4 个了。

事件循环将第 4 个回调函数推入调用栈,执行 console.log() 语句。

接着处理完 nextTick 队列之后,控制流程进入到 Promise 队列。Promise 队列与 nextTick 队列处理方式类似。

首先记录“Promise.resolve 1”,然后是“Promise.resolve 2”,这时因为调用 process.nextTick() 的原因,一个函数(译注:即 () => console.log("this is the inner next tick inside Promise then block") ) 被推入 nextTick 队列了。尽管如此,控制流程仍停留在 Promise 队列,因此还会继续执行队列中的其他函数。然后我们得到“Promise.resolve 3”,此时 Promise 队列为空。

Node.js 将再次检查微任务队列中是否有新的回调。由于 nextTick 队列中有一个回调,因此会执行这个回调,导致我们的最后一条日志输出。

this is process.nextTick 1
this is process.nextTick 2
this is process.nextTick 3
this is the inner next tick inside next tick
this is Promise.resolve 1
this is Promise.resolve 2
this is Promise.resolve 3
this is the inner next tick inside Promise then block

这可能是一个稍微高级的实验,但推论仍然相同。

推论

nextTick 队列中的所有回调函数优先于 Promise 队列中的回调函数执行。

使用 process.nextTick() 时要小心。过度使用此方法可能会导致事件循环饥饿,从而阻止队列中的其余部分运行。当存在大量的 nextTick() 调用时,I/O 队列是无法执行自己的回调函数的。官方文档建议使用 process.nextTick() 的两个主要场景:处理错误或在调用栈为空事件循环继续之前执行回调用。所以在使用 process.nextTick() 时,要明智一些。

总结

实验表明,用户编写的所有同步 JavaScript 代码优先于异步代码执行,并且 nextTick 队列中的所有回调函数优先于 Promise 队列中的回调函数执行。

原文链接:Visualizing nextTick and Promise Queues in Node.js Event Loop,2023年3月30日,by Vishwas Gopinath

更多node相关知识,请访问:nodejs 教程

以上是深入淺析Node事件循環中的微任務佇列的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:掘金社区。如有侵權,請聯絡admin@php.cn刪除
使用Next.js(後端集成)構建多租戶SaaS應用程序使用Next.js(後端集成)構建多租戶SaaS應用程序Apr 11, 2025 am 08:23 AM

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務

如何使用Next.js(前端集成)構建多租戶SaaS應用程序如何使用Next.js(前端集成)構建多租戶SaaS應用程序Apr 11, 2025 am 08:22 AM

本文展示了與許可證確保的後端的前端集成,並使用Next.js構建功能性Edtech SaaS應用程序。 前端獲取用戶權限以控制UI的可見性並確保API要求遵守角色庫

JavaScript:探索網絡語言的多功能性JavaScript:探索網絡語言的多功能性Apr 11, 2025 am 12:01 AM

JavaScript是現代Web開發的核心語言,因其多樣性和靈活性而廣泛應用。 1)前端開發:通過DOM操作和現代框架(如React、Vue.js、Angular)構建動態網頁和單頁面應用。 2)服務器端開發:Node.js利用非阻塞I/O模型處理高並發和實時應用。 3)移動和桌面應用開發:通過ReactNative和Electron實現跨平台開發,提高開發效率。

JavaScript的演變:當前的趨勢和未來前景JavaScript的演變:當前的趨勢和未來前景Apr 10, 2025 am 09:33 AM

JavaScript的最新趨勢包括TypeScript的崛起、現代框架和庫的流行以及WebAssembly的應用。未來前景涵蓋更強大的類型系統、服務器端JavaScript的發展、人工智能和機器學習的擴展以及物聯網和邊緣計算的潛力。

神秘的JavaScript:它的作用以及為什麼重要神秘的JavaScript:它的作用以及為什麼重要Apr 09, 2025 am 12:07 AM

JavaScript是現代Web開發的基石,它的主要功能包括事件驅動編程、動態內容生成和異步編程。 1)事件驅動編程允許網頁根據用戶操作動態變化。 2)動態內容生成使得頁面內容可以根據條件調整。 3)異步編程確保用戶界面不被阻塞。 JavaScript廣泛應用於網頁交互、單頁面應用和服務器端開發,極大地提升了用戶體驗和跨平台開發的靈活性。

Python還是JavaScript更好?Python還是JavaScript更好?Apr 06, 2025 am 12:14 AM

Python更适合数据科学和机器学习,JavaScript更适合前端和全栈开发。1.Python以简洁语法和丰富库生态著称,适用于数据分析和Web开发。2.JavaScript是前端开发核心,Node.js支持服务器端编程,适用于全栈开发。

如何安裝JavaScript?如何安裝JavaScript?Apr 05, 2025 am 12:16 AM

JavaScript不需要安裝,因為它已內置於現代瀏覽器中。你只需文本編輯器和瀏覽器即可開始使用。 1)在瀏覽器環境中,通過標籤嵌入HTML文件中運行。 2)在Node.js環境中,下載並安裝Node.js後,通過命令行運行JavaScript文件。

在Quartz中如何在任務開始前發送通知?在Quartz中如何在任務開始前發送通知?Apr 04, 2025 pm 09:24 PM

如何在Quartz中提前發送任務通知在使用Quartz定時器進行任務調度時,任務的執行時間是由cron表達式設定的。現�...

See all articles

熱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中的所有內容
3 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能