首頁 >web前端 >js教程 >Node.js中阻塞與非阻塞的講解

Node.js中阻塞與非阻塞的講解

不言
不言轉載
2018-11-15 17:30:551950瀏覽

這篇文章帶給大家的內容是關於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中文網其他相關文章!

陳述:
本文轉載於:https://segmentfault.com/a/1190000017016894。如有侵權,請聯絡admin@php.cn刪除