這篇文章帶給大家的內容是關於Node.js中阻塞與非阻塞的講解,有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。
阻塞與非阻塞概述
此概述介紹了Node.js中阻塞與非阻塞呼叫之間的區別,此概述將引用事件循環和libuv,但不需要事先了解這些主題,假設讀者對JavaScript語言和Node.js回呼模式有基本的了解。
「I/O」主要指與libuv支援的系統的磁碟和網路的交互作用。
阻斷是指在Node.js進程中執行其他JavaScript必須等到非JavaScript操作完成,發生這種情況是因為當發生阻塞操作時,事件循環無法繼續執行JavaScript 。
在Node.js中,由於CPU密集而不是等待非JavaScript操作而表現出較差效能的JavaScript,例如I/O,通常不稱為阻塞。 Node.js標準函式庫中使用libuv的同步方法是最常用的阻塞操作,原生模組也可能有阻塞方法。
Node.js標準庫中的所有I/O方法都提供非阻塞的非同步版本,並接受回呼函數,某些方法還具有對應的阻塞方法,其名稱以Sync
結尾。
阻塞方法同步執行,非阻塞方法非同步執行。
以檔案系統模組為例,這是一個同步讀取檔案的方法:
const fs = require('fs'); const data = fs.readFileSync('/file.md'); // blocks here until file is read
這是一個等效的非同步範例:
const fs = require('fs'); fs.readFile('/file.md', (err, data) => { if (err) throw err; });
第一個範例看起來比第二個範例更簡單,但缺點是第二行阻止執行任何其他JavaScript,直到讀取整個文件,請注意,在同步版本中,如果拋出錯誤,則需要捕獲它,否則進程將崩潰,在非同步版本中,由作者決定是否應該如圖所示拋出錯誤。
讓我們稍微擴展一下我們的例子:
const fs = require('fs'); const data = fs.readFileSync('/file.md'); // blocks here until file is read console.log(data); // moreWork(); will run after console.log
這是一個類似但不等同的非同步範例:
const fs = require('fs'); fs.readFile('/file.md', (err, data) => { if (err) throw err; console.log(data); }); // moreWork(); will run before console.log
在上面的第一個範例中,將在moreWork()
之前呼叫console.log
,在第二個範例中,fs.readFile()
是非阻塞的,因此JavaScript執行可以繼續,並且將首先呼叫moreWork()
,在不等待檔案讀取完成的情況下運行moreWork()
的能力是一個關鍵的設計選擇,可以提高吞吐量。
Node.js中的JavaScript執行是單執行緒的,因此並發性是指事件循環在完成其他工作後執行JavaScript回呼函數的能力,任何預期以並發方式運行的程式碼都必須允許事件循環繼續運行,因為非JavaScript操作(如I/O)正在發生。
作為一個例子,讓我們考慮這樣一種情況:每個Web伺服器請求需要50ms才能完成,50ms中的45ms是可以非同步完成的資料庫I/O,選擇非阻塞非同步操作可以釋放每個請求45毫秒來處理其他請求,僅透過選擇使用非阻塞方法而不是阻塞方法,這是容量的顯著差異。
事件循環不同於許多其他語言中的模型,其中可以建立其他執行緒來處理並發工作。
處理I/O時應該避免一些模式,我們來看一個例子:
const fs = require('fs'); fs.readFile('/file.md', (err, data) => { if (err) throw err; console.log(data); }); fs.unlinkSync('/file.md');
在上面的範例中,fs .unlinkSync()很可能在fs.readFile()之前執行,這會在實際讀取之前刪除file.md,寫一個更好的方法是完全無阻塞並保證以正確的順序執行:
const fs = require('fs'); fs.readFile('/file.md', (readFileErr, data) => { if (readFileErr) throw readFileErr; console.log(data); fs.unlink('/file.md', (unlinkErr) => { if (unlinkErr) throw unlinkErr; }); });
上面在fs.readFile()的回呼中對fs.unlink()進行了非阻塞調用,這保證了正確的操作順序。
#以上是Node.js中阻塞與非阻塞的講解的詳細內容。更多資訊請關注PHP中文網其他相關文章!