日常的學習筆記,包括 ES6、Promise、Node.js、Webpack、http 原理、Vue全家桶,后續可能還會繼續更新 Typescript、Vue3 和 常見的面試題 等等。
Node的基本概念
什么是Node?
Node.js是一個基於 Chrome V8 引擎的JavaScript運行環境(runtime),Node不是一門語言是讓js運行在后端的運行時,並且不包括javascript全集,因為在服務端中不包含DOM和BOM,Node也提供了一些新的模塊例如http、fs模塊等。Node.js 使用了事件驅動、非阻塞式 I/O 的模型,使其輕量又高效並且Node.js 的包管理器 npm,是全球最大的開源庫生態系統。到此我們已經對node有了簡單的概念。
Node的高並發
Node在處理高並發,I/O密集場景有明顯的性能優勢。
- 高並發,是指在同一時間並發訪問服務器。
- I/O密集指的是文件操作、網絡操作、數據庫,相對的有CPU密集,CPU密集指的是邏輯處理運算、壓縮、解壓、加密、解密。
Web主要場景就是接收客戶端的請求讀取靜態資源和渲染界面,所以Node非常適合Web應用的開發。
說到高並發,肯定就會想起多線程。那么多線程和高並發之間的關系和區別又是什么呢?
多線程
首先我們先來了解一下什么是多線程
后端語言(包括Java、C++等)存在一個線程池,每發送一次請求,線程池都會分配一個線程給服務器,用來處理請求,以此類推。因為多線程語言的特點是同步請求,所以在多線程發送請求時,可能會存在單個線程阻塞的情況,需要等待當前這個線程的任務處理完畢后,才會釋放線程並放回到線程池,方便下一批任務的使用。當前線程數超過線程池最大可分配數量時,可能就會出現等待的情況。
-
多線程優點:可以高效高速的處理多個api請求(圖片壓縮、大量計算 等...),屬於cpu密集型。
-
多線程缺點:不安全性,假設我們有多個線程需要對數據庫同一個資源進行操作(例如對同一個數據進行修改),就會出現數據安全性的問題 [需要對資源進行加鎖操作]。
多線程並非一起做某一件事,靠的是切換上下文(分時),所以多線程會浪費一些資源。
關於多線程的具體概念,可以去查閱相關的資料。
高並發
高並發是單線程的一個概念。
- 高並發優點:不需要開啟多個線程,節省資源。
- 高並發缺點:不適合做復雜操作,如果需要做復雜操作,可以開啟子進程。
Node是多線程的,但是其主線程是單線程。所以我們一直都說,Node其實是單線程語言。
同步異步和阻塞非阻塞
- 同步就是在執行某段代碼時,代碼沒有得到返回之前,其他代碼無法執行,當得到了返回值后可以繼續執行其他代碼。
- 異步就是在執行某段代碼時,代碼不會立即得到返回結果,可以繼續執行其他代碼,返回值通過回調來獲取。
關於同步阻塞與異步非阻塞,可以參考我之前的文章。
Node中的EventLoop
- 1.我們寫的js代碼會交給v8引擎進行處理。
- 2.代碼中可能會調用nodeApi,node會交給libuv庫處理
- 3.libuv通過阻塞i/o和多線程實現了異步io。
- 4.通過事件驅動的方式,將結果放到事件隊列中,最終交給我們的應用。
本階段執行已經被 setTimeout() 和 setInterval() 的調度回調函數。
┌───────────────────────────┐
┌─>│ timers │
│ └─────────────┬─────────────┘
| 執行延遲到下一個循環迭代的 I/O 回調。
│ ┌─────────────┴─────────────┐
│ │ pending callbacks │
│ └─────────────┬─────────────┘
| 僅系統內部使用。
│ ┌─────────────┴─────────────┐
│ │ idle, prepare │
│ └─────────────┬─────────────┘
| 檢索新的I/O事件;執行與 I/O相關的回調 ┌───────────────┐
│ ┌─────────────┴─────────────┐ │ incoming: │
│ │ poll │<─────┤ connections, │
│ └─────────────┬─────────────┘ │ data, etc. │
│ setImmediate() 回調函數在這里執行。 └───────────────┘
│ ┌─────────────┴─────────────┐
│ │ check │
│ └─────────────┬─────────────┘
| 一些關閉的回調函數
│ ┌─────────────┴─────────────┐
└──┤ close callbacks │
└───────────────────────────┘
這里每一個階段都對應一個事件隊列,當event loop執行到某個階段時會將當前階段對應的隊列依次執行。當該隊列已用盡或達到回調限制,事件循環將移動到下一階段。
process.nextTick()
從技術上講不是事件循環的一部分。優先級高於微任務
poll階段:
-
檢測Poll隊列中是否為空,如果不為空則執行隊列中的任務,直到超時或者全部執行完畢。
-
執行完畢后檢測setImmediate隊列是否為空,如果不為空則執行check階段,如果為空則等待時間到達。時間到達后回到timer階段
-
等待時間到達是可能會出現新的callback,此時也在當前階段被清空
本篇文章由莫小尚創作,文章中如有任何問題和紕漏,歡迎您的指正與交流。
您也可以關注我的 個人站點、博客園 和 掘金,我會在文章產出后同步上傳到這些平台上。
最后感謝您的支持!