摘要:異步編程在傳統編程實踐中,大多數操作都是同步發生的。中的異步編程異步是一種輸入輸出處理的形式,它允許在傳輸完成之前,其它處理能繼續進行。
本文轉載自:眾成翻譯
譯者:網絡埋伏紀事
鏈接:http://www.zcfy.cc/article/1759
原文:https://blog.risingstack.com/node-hero-async-programming-in-node-js/
本章我將指導你學習異步編程的原理,并向你展示如何在 JavaScript 和 Node.js 中實現異步編程。
異步編程在傳統編程實踐中,大多數 I/O 操作都是同步發生的。如果想想 Java,想想如何用 Java 讀取一個文件,你會得到下面這樣的代碼:
try(FileInputStream inputStream = new FileInputStream("foo.txt")) { Session IOUtils; String fileContent = IOUtils.toString(inputStream); }
這背后發生了什么?主線程會被阻塞,直到文件讀完,這意味著讀文件的同時其它什么事情都做不了。要解決此問題,更好利用 CPU,就不得不手動管理線程。
如果有更多阻塞操作,那么事件隊列就變得更糟糕:
(紅色塊表示在進程等待外部資源的響應而被阻塞時,黑色塊表示在代碼運行時,綠色塊表示應用的其余部分)
為解決這個問題,Node.js 引入了一種異步編程模型。
Node.js 中的異步編程異步 I/O 是一種輸入/輸出處理的形式,它允許在傳輸完成之前,其它處理能繼續進行。
在如下的示例中,我將展示 Node.js 中一個簡單的文件讀寫過程 - 同時采用同步和異步的方式,目的是向你展示通過避免阻塞應用程序,能實現什么。
下面我們先從一個簡單的示例開始 - 以同步的方式用 Node.js 讀一個文件:
const fs = require("fs") let content try { content = fs.readFileSync("file.md", "utf-8") } catch (ex) { console.log(ex) } console.log(content)
這里剛剛發生了什么?我們試圖用 fs 模塊的同步接口讀一個文件。它按預期方式工作 - content 變量會包含 file.md 的內容。這種方式的問題是,Node.js 會被阻塞,直到操作完成 - 也就是說在文件正在被讀取時,它什么事都做不了。
下面我們看看如何修復!
我們直到,在 JavaScript 中,異步編程只能用函數這個該語言的一等公民來實現:函數可以像所有其它變量一樣傳給其它函數。將其它函數作為參數的函數被稱為高階函數。
如下是一個高階函數的最簡單示例:
const numbers = [2,4,1,5,4] function isBiggerThanTwo (num) { return num > 2 } numbers.filter(isBiggerThanTwo)
在上例中,我們將一個函數傳遞給 filter 函數。通過這種方式我們可以定義過濾的邏輯。
這就是回調誕生的方式:如果你把一個函數傳遞給另一個函數作為參數,那么就可以在另一個函數完成任務時,在該函數內調用傳進來的函數。不需要返回值,只用值調用另一個函數。
這些所謂錯誤優先(error-first)的回調是 Node.js 本身的核心 - 核心模塊用了它,大多數 NPM 中的模塊也是。
const fs = require("fs") fs.readFile("file.md", "utf-8", function (err, content) { if (err) { return console.log(err) } console.log(content) })
這里要注意:
錯誤處理: 必須在回調中檢測錯誤,而不是用 try-catch 塊。
沒有返回值: 異步函數不返回值,但是值將被傳遞給回調。
下面我們對這個文件做點修改,看看它實際上是如何工作的:
const fs = require("fs") console.log("start reading a file...") fs.readFile("file.md", "utf-8", function (err, content) { if (err) { console.log("error happened during reading the file") return console.log(err) } console.log(content) }) console.log("end of the file")
這段腳本的輸出將是:
start reading a file... end of the file error happened during reading the file
正如你所見,一旦我們開始讀文件,執行繼續,應用程序打印出 end of the file。一旦文件讀取完成,我們的回調就只被調用一次。這怎么可能呢?迎接事件循環。
事件循環事件循環是 Node.js / JavaScript 的核心 - 它負責安排異步操作。
在深入了解之前,要確保理解什么是事件驅動的編程。
事件驅動的編程是一種編程范式,在這種范式中程序流程是由事件決定的,比如用戶行為(鼠標點擊、按鍵)、傳感器輸出或者其它程序/線程的消息。
實際上,它意味著應用程序按照事件行事。
并且,我們在第一章已經學過,從開發者的觀點看,Node.js 是單線程的。這意味著不必處理線程和線程同步,Node.js 遠離了這種復雜性。除了你的代碼,所有東西都是并行執行的。
要更深入理解事件循環,請繼續 youtube 上的視頻。
異步控制流至此你已經對 JavaScript 中的異步編程工作機制有了一個基本認識,下面我們來看看幾個如何組織代碼的示例。
Async.js為避免所謂回調地獄,可以做的一件事情是開始使用 async.js。
Async.js 幫助組織應用程序結構,讓流程控制更容易。
下面我們看一個使用 Async.js 的簡短示例,然后用 Promises 重寫。
如下的代碼片段映射三個文件上的狀態:
async.parallel(["file1", "file2", "file3"], fs.stat, function (err, results) { // 現在結果是是一個每個文件的狀態數組 })Promises
Promise 對象用于延遲及異步計算。一個 Promise 代表還沒有完成,但是未來會執行的操作。
在實踐中,前面的示例可以重寫為如下:
function stats (file) { return new Promise((resolve, reject) => { fs.stat(file, (err, data) => { if (err) { return reject (err) } resolve(data) }) }) } Promise.all([ stats("file1"), stats("file2"), stats("file3") ]) .then((data) => console.log(data)) .catch((err) => console.log(err))
當然,如果使用一個有 Promise 接口的方法,那么 Promise 示例的行數也會少很多。
下一步:第一個 Node.js 服務器下一章將會學習如何啟動第一個 Node.js HTTP 服務器。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/84981.html
摘要:使用一個事件驅動的非阻塞式的模型,讓它輕量而高效。也就是說提供了用編寫服務器的可能性,這種服務器具有令人難以置信的性能。正如官方聲明所說是一個使用與瀏覽器相同引擎的運行時。這意味著有兩個發布版本穩定版和試驗版。 本文轉載自:眾成翻譯譯者:網絡埋伏紀事鏈接:http://www.zcfy.cc/article/1748原文:https://blog.risingstack.com/nod...
摘要:網站和使用同樣的注冊庫來顯示模塊以及查找模塊。使用在上一章開始使用中,當創建文件時,已經遇到了。此外,全局命名空間只包含公共模塊。通過引入作用域包來解決此問題。下一步異步編程下一章學習使用回調和實現異步編程的原理。 本文轉載自:眾成翻譯譯者:網絡埋伏紀事鏈接:http://www.zcfy.cc/article/1749原文:https://blog.risingstack.com/n...
摘要:本文是響應式編程第四章構建完整的應用程序這篇文章的學習筆記。涉及的運算符每隔指定時間將流中的數據以數組形式推送出去。中提供了一種叫做異步管道的模板語法,可以直接在的微語法中使用可觀測對象示例五一點建議一定要好好讀官方文檔。 本文是【Rxjs 響應式編程-第四章 構建完整的Web應用程序】這篇文章的學習筆記。示例代碼托管在:http://www.github.com/dashnoword...
摘要:本教程會學習如何正確組織一個項目的結構,從而在應用程序開始增長時避免混亂。項目結構的五個基本規則組織項目有不少可能的方式并且每種已知的方式都有其興衰。過去在,我們有機會創建各種規模的高效應用程序,也獲得了大量關于項目結構注意事項的見解。 本文轉載自:眾成翻譯譯者:網絡埋伏紀事鏈接:http://www.zcfy.cc/article/1756原文:https://blog.rising...
摘要:可能因為先入為主,在編程之中,往往不由自主地以的邏輯編程思路設計模式進行開發。這是原型模式很重要的一條原則。關于閉包與內存泄露的問題,請移步原型模式閉包與高階函數應該可以說是設計模式的基礎要領吧。在下一章,再分享一下的幾種常用設計模式。 前 在學習使用Javascript之前,我的程序猿生涯里面僅有接觸的編程語言是C#跟Java——忽略當年在大學補考了N次的C與VB。 從靜態編程語言,...
閱讀 2954·2021-11-11 16:55
閱讀 515·2021-09-27 13:36
閱讀 1073·2021-09-22 15:35
閱讀 2908·2019-08-30 12:46
閱讀 3125·2019-08-26 17:02
閱讀 1826·2019-08-26 11:56
閱讀 1295·2019-08-26 11:47
閱讀 423·2019-08-23 17:01