摘要:標準庫中的所有方法都提供非阻塞的異步版本,并接受回調函數,某些方法還具有對應的阻塞方法,其名稱以結尾。比較代碼阻塞方法同步執行,非阻塞方法異步執行。
阻塞與非阻塞概述
此概述介紹了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()進行了非阻塞調用,這保證了正確的操作順序。
其他資源libuv
關于Node.js
上一篇:遷移到安全的Buffer構造函數 下一篇:Node.js事件循環、定時器和process.nextTick()文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/108575.html
Node.js 指南 Node.js?是基于Chrome的V8 JavaScript引擎構建的JavaScript運行時。 常規 關于Node.js 入門指南 輕松分析Node.js應用程序 Docker化Node.js Web應用程序 遷移到安全的Buffer構造函數 Node.js核心概念 阻塞與非阻塞概述 Node.js事件循環、定時器和process.nextTick() 不要阻塞事...
摘要:如果不熟悉這種語言,有一篇關于阻塞與非阻塞的完整文章。在設計上與的或的等系統類似,并受其影響,進一步采用事件模型。它將事件循環呈現為運行時構造而不是庫,在其他系統中,始終存在阻塞調用以啟動事件循環。上一篇指南目錄下一篇入門指南 關于Node.js 作為異步事件驅動的JavaScript運行時,Node旨在構建可伸縮的網絡應用程序,在下面的hello world示例中,可以同時處理許多連...
摘要:檢索新的事件執行與相關的回調幾乎所有,除了由定時器調度的一些和將在適當的時候在這里阻塞。在事件循環的每次運行之間,檢查它是否在等待任何異步或定時器,如果沒有,則徹底關閉。 Node.js事件循環、定時器和process.nextTick() 什么是事件循環? 事件循環允許Node.js執行非阻塞I/O操作 — 盡管JavaScript是單線程的 — 通過盡可能將操作卸載到系統內核。 ...
摘要:回調函數在完成任務后就會被調用,使用了大量的回調函數,所有的都支持回調函數。因此,阻塞是按順序執行的,而非阻塞是不需要按順序的,所以如果需要處理回調函數的參數,我們就需要寫在回調函數內。 Node.js異步變成的直接體現就是回調。異步編程依托于回調來實現,但不能說使用了回調后程序就異步化了?;卣{函數在完成任務后就會被調用,Node使用了大量的回調函數,Node所有的APi都支持回調函數...
摘要:在回調隊列中,函數等待調用棧為空,因為每個語句都執行一次。最后一個運行,并且從調用棧中彈出。它將回調以先進先出順序移動到調用棧并執行。 翻譯:瘋狂的技術宅原文: https://medium.freecodecamp.o... 本文首發微信公眾號:前端先鋒歡迎關注,每天都給你推送新鮮的前端技術文章 Node.js 是一個 JavaScript 運行時環境。聽起來還不錯,不過這究竟...
閱讀 4943·2021-11-25 09:43
閱讀 1191·2021-11-24 09:38
閱讀 1902·2021-09-30 09:54
閱讀 2807·2021-09-23 11:21
閱讀 2371·2021-09-10 10:51
閱讀 2375·2021-09-03 10:45
閱讀 1170·2019-08-30 15:52
閱讀 1771·2019-08-30 14:13