>[success] # node 中常用的IO
Node.js 是一個基于事件驅動、非阻塞I/O模型的JavaScript運行時,因此在 Node.js 中,I/O 操作是非常重要的一部分。以下是 Node.js 中常用的 I/O 操作:
1. 文件 I/O:Node.js 提供了一組文件系統(fs)API,可以對文件進行讀寫操作,例如:讀取文件、寫入文件、創建目錄和刪除文件等。
2. 網絡 I/O:Node.js 提供了一組網絡 API,可以創建和管理網絡連接,例如:創建 HTTP/HTTPS 服務器、創建 TCP/UDP 客戶端等,還可以使用 Socket.IO 等庫進行 WebSocket 編程。
3. 控制臺 I/O:Node.js 提供了控制臺輸出 API,例如:console.log()、console.error() 等,可以在控制臺輸出日志信息。
4. 進程 I/O:Node.js 提供了一組進程 API,可以對進程進行管理,例如:創建子進程、發送信號等。
5. 事件 I/O:Node.js 是基于事件驅動的,因此事件 I/O 是非常重要的一部分。Node.js 提供了一組事件相關的 API,例如:EventEmitter、process.nextTick() 等。
>[success] # 理解node 中 I/O
`Node.js`的**I/O模型屬于事件驅動和異步I/O模型**。這種設計使得 Node.js 可以通過事件驅動和異步 I/O 處理**大量并發連接或文件訪問**。因此**非阻塞 I/O 的特性,使得它在處理高并發場景下具有很好的性能**。
`Node.js` 提供了多種 `API `來支持各種 I/O 操作,**包括文件系統操作,網絡操作**等。由于 `Node.js`
[圖片來自](https://juejin.cn/book/7171733571638738952/section/7172100279058300935)

>[danger] ##### node 中異步I/O模型
在 `Node.js` 中,`I/O` 操作的實現方式是**異步非阻塞的模型**,即當發起一個` I/O `請求時,`Node.js` 并不會阻塞主線程的執行,而是將其放到一個專門的 `I/O` 線程中執行,**然后通過事件循環機制等待 I/O 線程完成操作,將結果返回給主線程進行后續處**
*****
不是說`js` 是單線程么,怎么出現了一個 `I/O` 線程?**node單線程是對我們觀察而言。對底層可不是,只不過其他線程對你不開放的**,如果node真的只是單純的單線程那么就變成**同步阻塞模型**,這種模型下的 I/O 操作會阻塞主線程的執行,直到 I/O 操作完成并返回結果后才能繼續執行后面的代碼。這種模型在高并發的情況下效率低下,容易導致系統瓶頸和響應延遲。
>[info] ## node 的事件循環機制
我們知道 JS 是單線程的(node并不是),如果線程池處理完一個任務之后,直接執行上層回調,上層代碼就完全亂了。這時候就需要一個**異步通知的機制**,也就是說當一個線程處理完任務的時候,它不是直接去執行上程回調的,而是**通過異步機制去通知主線程來執行這個回調**
*****
在node 的I/O線程執行完的數據是怎么回到主線程。這個過程,I/O操作則委托給`libuv`庫處理,`libuv`會將I/O操作分發到系統線程池中的線程中進行處理,當`I/O`操作完成時,線程會將結果通知到`libuv`,`libuv`再將結果通知到`JavaScript`線程,`JavaScript`線程再執行回調函數處理結果。**這個過程有點像發布訂閱,將耗時的 I/O 操作交給其他線程或者線程池來完成,然后在主線程中繼續執行其他任務,等到 I/O 操作完成后再通過回調函數或者事件來通知主線程獲取返回結果**例如,如果是文件讀取即讀取的內容已經在I/O 線程執行獲取完了
>[danger] ##### libuv
`libuv `是 Node.js 的一個重要的跨平臺庫,主要用于處理 I/O 操作、文件系統訪問、網絡操作、定時器等異步操作。它的作用在于提供一個事件循環機制,用于管理 Node.js 的異步操作,并支持在多個平臺上的異步事件處理。libuv 采用非阻塞 I/O 的方式,可以支持 Node.js 處理大量并發連接或文件訪問,從而保證了 Node.js 在處理高并發場景下的性能和穩定性。Node.js 中受到 libuv 的管理的事件,基本都是通過回調函數的方式來處理的。同時,libuv 還提供了線程池機制,**可以用于處理 CPU 密集型的任務,以減輕主線程的壓力,從而避免造成阻塞。**
* 我們編寫的JavaScript代碼會經過V8引擎,再通過Node.js的Bindings,將任務放到Libuv的事件循環中;libuv(Unicorn Velociraptor—獨角伶盜龍)是使用C語言編寫的庫;libuv提供了**事件循環、文件系統讀寫、網絡IO、線程池**等等內容;在對應的線程位置(workThreads)處理對應的模塊,處理完后將結果在(executecallback)在回到對應的事件隊列中

>[danger] ##### 瀏覽器中的事件循環機制
在瀏覽器中,JavaScript 代碼是運行在主線程中的,如果執行一個耗時的 I/O 操作,比如發送 AJAX 請求,就會阻塞主線程,導致用戶界面無響應或卡頓。
為了避免這個問題,瀏覽器的網絡模塊通常是運行在獨立的線程中的,這個線程叫做網絡線程(network thread)。當 JavaScript 代碼調用異步 API 發起網絡請求時,瀏覽器會將這個請求交給網絡線程去處理,然后立即返回到 JavaScript 代碼中執行下一行代碼。網絡線程會在后臺執行這個 I/O 操作,等到 I/O 操作完成后,就會觸發一個事件,告訴 JavaScript 代碼請求已經完成,可以獲取返回結果了。
由于 JavaScript 代碼是運行在主線程中的,因此網絡請求的結果不能直接返回給 JavaScript 代碼,而是需要通過事件回調的方式來完成。當網絡線程完成請求后,它會將請求結果傳遞給瀏覽器的主線程(也就是 JavaScript 線程),然后觸發相應的事件,告訴 JavaScript 代碼請求已經完成,可以獲取返回結果了。這個過程是通過事件驅動來實現的。
>[danger] ##### 二者總結
[瀏覽器與Node的事件循環(Event Loop)有何區別? | Fundebug博客 - 一行代碼搞定BUG監控 - 網站錯誤監控|JS錯誤監控|資源加載錯誤|網絡請求錯誤|小程序錯誤監控|Java異常監控|監控報警|Source Map|用戶行為|可視化重現](https://blog.fundebug.com/2019/01/15/diffrences-of-browser-and-node-in-event-loop/)
**Node.js 是通過 libuv 庫來實現異步 I/O 操作和事件循環機制的,而瀏覽器是通過 Web API 實現異步操作**,同時也采用了事件循環機制來保證異步操作的高效執行。無論是在 Node.js 還是在瀏覽器中,事件循環機制都是實現異步編程的關鍵,通過將異步操作的回調函數注冊到事件循環中,可以保證異步操作的非阻塞和高效執行。
>[danger] ##### 深入案例
當需要從數據庫中查詢數據并返回給客戶端時,可以使用同步和異步兩種方式來實現: 同步方式:
~~~javascript
javascriptCopy codeconst http = require('http');
const mysql = require('mysql');
const connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'password',
database: 'test'
});
const server = http.createServer((req, res) => {
const result = connection.query('SELECT * FROM users'); // 同步查詢數據庫
res.end(JSON.stringify(result)); // 返回結果給客戶端
});
server.listen(3000, () => {
console.log('Server is running at http://localhost:3000');
});
~~~
在上面的代碼中,使用了同步方式查詢數據庫,這會阻塞程序的執行,直到查詢完成并返回結果。在查詢期間,程序無法處理其他的請求,因此會導致程序的性能下降。 異步方式:
~~~javascript
javascriptCopy codeconst http = require('http');
const mysql = require('mysql');
const connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'password',
database: 'test'
});
const server = http.createServer((req, res) => {
connection.query('SELECT * FROM users', (err, result) => { // 異步查詢數據庫
if (err) {
return console.error(err);
}
res.end(JSON.stringify(result)); // 返回結果給客戶端
});
});
server.listen(3000, () => {
console.log('Server is running at http://localhost:3000');
});
~~~
在上面的代碼中,使用了異步方式查詢數據庫,這不會阻塞程序的執行,而是將查詢操作放到一個隊列中,然后立即返回結果給客戶端。當查詢完成后,會調用回調函數將查詢結果返回給客戶端。這種方式可以充分利用系統的資源,提高程序的性能和并發處理能力。
???????????
https://juejin.cn/post/7002106372200333319#heading-0
- 基礎
- 什么是Node.js
- 理解 I/O 模型
- 理解node 中 I/O
- 對比node 和java 使用場景
- node 模塊管理
- 內置模塊 -- buffer
- 內置模塊 -- fs
- fs -- 文件描述符
- fs -- 打開文件 api
- fs -- 文件讀取 api
- fs -- 文件寫入 api
- fs -- 創建目錄 api
- fs -- 讀取文件目錄結構 api
- fs -- 文件狀態(信息) api
- fs -- 刪除文件/目錄 api
- fs -- 重命名 api
- fs -- 復制文件 api
- 內置模塊 -- events
- 內置模塊 -- stream
- 可讀流 -- Readable
- 可寫流 -- Writable
- Duplex
- Transform
- 內置模塊 -- http
- http -- 從客戶端發起
- http -- 從服務端發起
- 內置模塊 -- url
- 網絡開發