JavaShuo
欄目
標籤
[書籍精讀]《深刻淺出Node.js》精讀筆記分享
時間 2020-05-21
標籤
書籍
精讀
深刻淺出Node.js
筆記
分享
欄目
Node.js
简体版
原文
原文鏈接
寫在前面
書籍介紹:本書由首章Node介紹爲索引,涉及Node的各個方面,主要內容包含模塊機制的揭示、異步I/O實現原理的展示、異步編程的探討、內存控制的介紹、二進制數據Buffer的細節、Node中的網絡編程基礎、Node中的Web開發、進程間的消息傳遞、Node測試以及經過Node構建產品須要的注意事項。
個人簡評:這是一本可貴的好書,這本書理論和實踐結合的很好。若是你是一個純前端的開發者,這本書能夠讀讀開拓些視野,若是你是一個全棧的開發者,這本書做爲入門和深刻後端也很不錯,推薦拜讀。
!!文末有pdf書籍、筆記思惟導圖、隨書代碼打包下載地址,須要請自取!閱讀[書籍精讀系列]全部文章,請移步:
推薦收藏-JavaScript書籍精讀筆記系列導航
第一章 Node簡介
1.1.Node的誕生歷程
2009年3月, Ryan Dahl
1.2.Node的命名與起源
別名 Nodejs、 NodeJS、 Node.js
找到了設計高性能, Web服務器的幾個要點: 事件驅動、非阻塞I/O
JavaScript 高性能、符合事件驅動、沒有歷史包袱
構建網絡應用的一個基礎框架
1.3.Node給JavaScript帶來的意義
瀏覽器中除了V8做爲JavaScript引擎外,還有一個WebKit佈局引擎
瀏覽器經過事件驅動來服務界面上的交互, Node經過過事件驅動來服務I/O
1.4.Node的特色
異步I/O、事件與回調函數、單線程、跨平臺
單線程:弱點1:沒法利用多核CPU;弱點2:錯誤會引發整個應用退出,應用的健壯性值得考驗;弱點3:大量計算佔用CPU致使沒法繼續調用異步I/O;Node採用與Web Workers相同的思路來解決單線程中大計算量的問題:child_process;
跨平臺:在操做系統與Node上層模塊系統之間構建了一層平臺層架構,即libuv;Node的第三方C++模塊也能夠藉助libuv實現跨平臺;
1.5.Node的應用場景
I/O密集型:面向網絡且擅長並行I/O
是否不擅長CPU密集型業務:採用使用多線程的方式進行計算;經過編寫C++擴展的方式更高效利用CPU;
與遺留系統和平共處
分佈式應用:數據平臺、數據庫集羣
1.6.Node的使用者
先後端編程語言環境統一
Node帶來的高性能I/O用於實時應用
並行I/O使得使用者能夠更高效的利用分佈式環境
並行I/O,有效利用穩定接口提高Web渲染能力
雲計算平臺提供Node支持
遊戲開發領域
工具類應用
第二章 模塊機制
大體經歷了工具類庫、組件庫、前端框架、前端應用的變遷
2.1.CommonJS規範
CommonJS的出發點:規範薄弱,如下缺陷(沒有模塊系統、標準庫較少、沒有標準接口、缺少包管理系統)
CommonJS的模塊規範:主要分爲模塊引用、模塊定義和模塊標識3個部分
2.2.Node的模塊實現
優先從緩存加載:瀏覽器僅僅緩存文件,而Node緩存的是編譯和執行以後的對象
路徑分析和文件定位:Node 會按.js、.json、.node的次序補足擴展名
模塊編譯:每個編譯成功的模塊都會將其文件路徑做爲索引緩存在Module._cache對象上;在編譯的過程當中,Node對獲取的JavaScript文件內容進行頭尾包裝;(function(exports, require, module, __filename, __dirname) {\n, 在尾部添加了\n});C/C++模塊,Node調用process.dlopen()方法進行加載和執行;
2.3.核心模塊
JavaScript核心模塊的編譯過程:C/C++文件放在Node項目的src目錄下,JavaScript文件存放在lib目錄下;編譯程序須要將全部的JavaScript模塊文件編譯爲C/C++代碼;
C/C++核心模塊的編譯過程:Node在啓動時,會生成一個全局變量process,並提供Binding()方法來協助內建模塊
2.4.C/C++擴展模塊
說明:JavaScript的一個典型弱點就是位運算;*nix下經過g++/gcc等編譯器編譯爲動態連接共享對象文件.so,Windows下則須要經過VisualC++的編譯器編譯爲動態連接庫文件.dll;
前提條件:GYP項目生成工具、V8引擎C++庫、libuv庫、Node內部庫、等等
C/C++擴展模塊的編寫:普通的擴展模塊與內建模塊的區別在於無需將源代碼編譯進Node,而是經過dlopen()方法動態加載
C/C++擴展模塊的編譯:寫好.gyp項目文件是除編碼外的頭等大事;編譯過程會根據平臺不一樣,分別經過make或者vcbuild進行編譯;
C/C++擴展模塊的加載:require()方法經過解析標識符、路徑分析、文件定位,而後加載執行便可;加載.node文件實際上經歷了兩個步驟,第一個步驟是掉用uv_dlopen方法去打開動態連接庫,第二個步驟調用uv_dlsym()方法找到動態連接庫中經過NODE_MODULE宏定義的方法地址;
2.5.模塊調用棧
JavaScript核心模塊主要扮演的職責有兩類:一類是做爲C/C++內建模塊的封裝層和橋接層,供文件模塊調用;一類是純粹的功能模塊,不須要跟底層打交道
2.6.包和NPM
包描述文件與NPM:包規範的定義能夠幫助Node解決依賴包安裝的問題;NPM實際須要的字段主要有name、version、description、keywords、repositories、author、bin、main、scripts、engines、dependencies、devDependencies;
NPM經常使用功能:NPM幫助完成了第三方模塊的發佈、安裝和依賴;查看幫助npm、分析包npm ls;
局域NPM:可以享受到NPM上衆多的包,同時對本身的包進行保密和限制
NPM潛在問題:開發人員水平不一,包質量也參差不齊;NPM模塊首頁上的依賴榜能夠說明模塊的質量和可靠性;GitHub上項目的觀察者數量和分支數量從側面反映模塊的可靠性和流行度;計劃引入CPAN社區中的Kwalitee風格來讓模塊進行天然排序;
2.7.先後端共用模塊
模塊的側重點:前端經過網絡加載代碼,瓶頸在於帶寬,後端從磁盤加載,瓶頸在於CPU和內存等資源
AMD規範:AMD模塊須要用define來明肯定義一個模塊,而在Node實現中是隱式包裝的
CMD規範:CMD與AMD規範的主要區別在於定義模塊和依賴引入的部分
兼容多種模塊規範:包裝兼容Node、AMD、CMD以及常見的瀏覽器環境中
第三章 異步IO
伴隨着異步I/O的還有事件驅動和單線程
3.1.爲何要異步I/O
用戶體驗:I/O是昂貴的,分佈式I/O是更昂貴的
資源分配:利用單線程,遠離多線程死鎖、狀態同步等問題;利用異步I/O,讓單線程遠離阻塞,以更好的使用CPU
3.2.異步I/O與實現現狀
異步I/O在Node中應用最爲普遍,可是它並不是Node的原創
異步I/O與非阻塞I/O:操做系統內核對於I/O只有兩種方式:阻塞與非阻塞;現存的輪詢技術主要有:read,select,poll,epoll,kequeue(read:重複調用來檢查I/O的狀態來完成完整數據的讀取;select:經過對文件描述符上的事件狀態來進行判斷;poll:採用鏈表的方式避免數組長度的限制,其次能避免不須要的檢查;epoll:Linux下效率最高的I/O事件通知機制;kqueue:與epoll相似,不過僅在FreeBSD系統下存在)
理想的非阻塞異步I/O
現實的異步I/O:在Node中,不管是*nix仍是Windows平臺,內部完成I/O任務的另有線程池
3.3.Node的異步I/O
事件循環:Node自身的執行模型:事件循環
觀察者:在Node中,事件主要來源於網絡請求、文件I/O等;在Windows下,這個循環基於IOCP建立,而在*nix下則基於多線程建立;
請求對象:從JavaScript發起調用到內核執行完I/O操做的過渡過程當中存在的一種中間產物
執行回調:事件循環、觀察者、請求對象、I/O線程池這四者共同構成Node異步I/O模型的基本要素;完成異步I/O的過程(Windows下經過IOCP向系統內核發送I/O調用和從內核獲取已完成的I/O操做,配以事件循環;Linux下經過epoll實現;FreeBSD下經過kqueue實現;Solaris下經過Event ports實現)
3.4.非I/O的異步API
與I/O無關的異步API:setTimeout()、setInterval()、setImmedate()、process.nextTick()
定時器:實現原理與異步I/O比較相似,只是不須要I/O線程池的參與;問題在於並不是精確的;
process.nextTick():採用定時器須要動用紅黑樹,建立定時器對象和迭代等操做;定時器中採用紅黑樹的操做時間複雜度爲O(lg(n)),nextTick()的時間複雜度爲O(1);
setImmediate():process.nextTick()中的回調函數執行的優先級要高於setImmediate();process.nextTick()屬於idle觀察者,setImmediate()屬於check觀察者;
3.5.事件驅動與高性能服務器
Node無需爲每個請求建立額外的對應線程
不受線程上下文切換開銷的影響
一些知名的基於事件驅動的實現:Ruby的Event Machine;Perl的AnyEvent;Python的Twisted;
第四章 異步編程
Node是首個將異步大規模帶到應用層面的平臺
4.1.函數式編程
高階函數:高階函數是能夠把函數做爲參數,或是將函數做爲返回值的函數
偏函數用法:偏函數用法是指建立一個調用另一個部分參數或變量已經預置的函數的函數的用法;經過指定部分參數來產生一個新的定製函數的形式就是偏函數;
4.2.異步編程的優點與難點
優點:Node的異步模型和V8的高性能
難點:異常處理、函數嵌套、阻塞代碼、多線程編程、異步轉同步
4.3.異步編程解決方案
事件發佈/訂閱模式:若是一個事件添加了超過10個偵聽器將會獲得一條警告,使用emitter.setMaxListeners(0)去掉限制
Promise/Deferred模式:Deferred主要是用於內部,用於維護異步模型的狀態;Promise則做用與外部,經過then()方法暴露給外部以添加自定義邏輯;Promise/Deferred模式將業務中不可變的部分封裝在了Deferred,將可變的部分交給Promise;
流程控制庫:尾觸發與Next,目前應用最多的地方是Connect的中間件;async,長期佔據NPM依賴榜的前三名,series實現異步的串行執行,parallel實現異步的並行執行,waterfall實現異步調用的依賴處理;step,更輕量;wind,思路徹底不一樣的異步編程方案;
4.4.異步併發控制
同步I/O,每一個I/O都是彼此阻塞的,不會出現耗用文件描述符太多的狀況
bagpip的解決方案:bagpipe模塊的解決思路(經過一個隊列來控制併發量;調用發起但未執行的異步調用量小於限定值,從隊列中取出執行;若是活躍調用達到限定值,調用暫時存放在隊列中;每個異步調用結束時,從隊列中取出新的異步調用執行;);拒絕訪問;超時控制;
async的解決方案:async中parallelLimit()用於處理異步調用的限制
第五章 內存控制
基於無阻塞、事件驅動創建的Node服務,具備內存消耗低的優勢,很是適合處理海量的網絡請求
5.1.V8的垃圾回收機制與內存限制
Node與V8
V8的內存限制:只能使用部份內存(64位系統下約爲1.4G,32位系統下約爲0.7G)
V8的對象分配:V8依然提供選項讓咱們使用更多的內存;--max-old-space-size設置老生代內存空間的最大值;--max-new-space-size設置新生代內存空間大小;
V8的垃圾回收機制:垃圾回收策略主要基於分代式垃圾回收機制;在分代的基礎上,新生代的對象主要經過Scavenge算法進行垃圾回收;V8在老生代中主要採用Mark-Sweep和Mark-Compact相結合的方式進行垃圾回收;
查看垃圾回收日誌:在啓動時添加--trace-gc參數;node啓動時使用--prof參數,能夠獲得V8執行時的性能分析數據;提供linux-tick-processor工具用於統計日誌信息;
5.2.高效使用內存
做用域:能造成做用域的有函數調用、with以及全局做用域
閉包:實現外部做用域訪問內部做用域中變量的方法
沒法當即回收的內存有閉包和全局變量引用這兩種狀況
5.3.內存指標
查看內存使用狀況:process.memoryUsage()能夠看到Node進程的內存佔用狀況;os模塊的totalmem()和freemem()查看系統的總內存和閒置內存;
堆外內存:不經過V8分配的內存稱爲堆外內存;利用堆外內存能夠突破內存限制的問題;
5.4.內存泄露
形成內存泄露的緣由幾個:緩存、隊列消費不及時、做用域未釋放
慎將內存看成緩存:在Node中任何試圖拿內存當緩存的行爲都應當被限制
關注隊列狀態:使任何異步調用的回調都具有可控的響應時間
5.5.內存泄露排查
常見的用於定位Node應用內存泄露的工具:v8-profiler、node-headpdump、node-mtrace、dtrace、node-memwatch
node-headdump
node-memwatch
5.6.大內存應用
Node提供了stream模塊用於處理大文件
要當心,即便V8不限制堆內存的大小,物理內存依然有限制
第六章 理解Buffer
6.1.Buffer結構
模塊結構:Buffer是一個像Array的對象,但它主要用於操做對象
Buffer對象:
buf[10]
的元素值是一個0到255的隨機值
Buffer內存分配:Buffer對象的內存分配不是在V8的堆內存中,而是在Node的C++層面實現內存的申請的;Node以8KB爲界限來區分Buffer是大對象仍是小對象;真正的內存是在Node的C++層面提供的,JavaScript層面只是使用它;
6.2.Buffer的轉換
目前支持的字符串編碼類型:ASCII、UTF-八、UTF-16LE/UCS-二、Base6四、Binary、Hex
字符串轉Buffer
Buffer轉字符串
Buffer不支持的編程類型:Buffer提供一個isEncoding()函數來判斷編碼是否支持轉換;iconv和iconv-lite兩個模塊能夠支持更多的編碼類型轉換;
6.3.Buffer的拼接
亂碼是如何產生的
setEncode()與string_decoder()
正確拼接Buffer:調用Buffer.concat()方法生成一個合併的Buffer對象
6.4.Buffer與性能
Buffer在文件I/O和網絡I/O中運用普遍
Buffer是二進制數據,字符串與Buffer之間存在編碼關係
第七章 網絡編程
Node提供了net、dgram、http、https這4個模塊,分別用於處理TCP、UDP、HTTP、HTTPS
7.1.構建TCP服務
TCP
建立TCP服務器端
TCP服務的事件:TCP套接字是可寫可讀的Stream對象,能夠利用pipe()方法巧妙的實現管道操做
7.2.構建UDP服務
建立UDP套接字
建立UDP服務器端
建立UDP客戶端
UDP套接字事件:UDP套接字只是一個EventEmitter的實例,而非Stream的實例
7.3.構建HTTP服務
HTTP
http模塊:TCP服務以connection爲單位進行服務,HTTP服務以request爲單位進行服務
HTTP客戶端
7.4.構建WebSocket服務
WebSocket握手
WebSocket的數據傳輸
7.5.網絡服務與安全
Node在網絡安全上提供了3個模塊,分別爲crypto、tls、https
TLS/SSL
TLS服務
HTTPS服務
第八章 構建Web應用
8.1.基礎功能
請求方法
路徑解析
查詢字符串
Cookie:Cookie處理的幾步(服務器向客戶端發送cookie;瀏覽器將Cookie保存;以後每次瀏覽器都會將Cookie發向服務器端)
Session:常見的兩種實現方式(基於Cookie來實現用戶和數據的映射;經過查詢字符串來實現瀏覽器端和服務器端數據的對應);Connect默認採用connect_uid,Tomcat會採用jsessionid等;
緩存:提升性能,YSlow中提到的幾條關於緩存的規則(添加Expires或Cache-Control到報文中;配置ETags;讓Ajax可緩存)
Basic認證:經過Base64加密後在網絡中傳送,有太多的缺點
8.2.數據上傳
表單數據:經過報頭的Transfer-Encoding或Content-Length便可判斷請求中是否帶有內容
附件上傳:瀏覽器在遇到multipart/form-data表單提交時,構造的請求報文與普通表單徹底不一樣;formidable,基於流式處理解析報文,將接收到的文件寫入到系統的臨時文件夾中,並返回對應的路徑;
數據上傳與安全
8.3.路由解析
文件路徑型
MVC
RESTful
8.4.中間件
異常處理
中間件與性能
從凌亂的發散狀態收斂成很規整的組織方式
8.5.頁面渲染
內容響應:不一樣的文件類型具備不一樣的Mime值;Content-Disposition字段影響的行爲是客戶端會根據它的值判斷是應該將報文數據看成即時瀏覽的內容,仍是可下載的附件;
視圖渲染
模板:實質就是將模板文件和數據經過模板引擎生成最終的HTML代碼;造成模板技術4個要素(模板語言;包含模板語言的模板文件;擁有動態數據的數據對象;模板引擎);mustache,弱邏輯的模板;最知名的有EJS、Jade等;
Bigpipe:用於調用限流,解決重數據頁面的加載速度問題;解決思路是將頁面分割成多個部分,先向用戶輸出沒有數據的佈局,將每一個部分逐步輸出到前端,再最渲染填充框架,完成整個網頁的渲染;
第九章 玩轉進程
9.1.服務模型的變遷
石器時代:同步 - 只在一些無併發要求的應用中存在
青銅時代:複製進程 - 要複製較多的數據,啓動是較爲緩慢的
白銀時代:多進程 - 時間將會被耗用在上下文切換中
黃金時代:事件驅動 - 內存耗用的問題著名的C10k問題;單線程避免了沒必要要的內存開銷和上下文切換開銷;
9.2.多進程架構
child_process.fork()複製的都是一個獨立的進程,獨立而全新的V8實例
啓動多個進程只是爲了充分將CPU資源利用起來,而不是爲了解決併發問題
建立子進程
進程間通訊:JavaScript主線程與UI渲染共用同一個線程;實現進程間通訊的技術有不少,如命名管道、匿名管道、socket、信號量、共享內存、消息隊列、Domain Socket等;操做系統的文件描述符是有限的;
句柄傳遞:句柄是一種能夠用來標識資源的引用,它的內部包含了指向對象的文件描述符;文件描述符其實是一個整數值;Node進程之間只有消息傳遞,不會真正的傳遞對象;
9.3.集羣穩定之路
進程事件
自動重啓:建立新工做進程在前,退出異常進程在後
負載均衡:輪叫調度的工做方式是由主進程接受鏈接,將其依次分發給工做進程
狀態共享:解決數據共享最簡單、直接的方式就是經過第三方進行數據存儲;主動通知;
9.4.Cluster模塊
Cluster工做原理:事實上是child_process和net模塊的組合應用
Cluster事件
第十章 測試
10.1.單元測試
編寫可測試代碼的幾個原則:單一職責、接口抽象、層次分離;
單元測試主要包含斷言、測試框架、測試用例、測試覆蓋率、mock、持續繼承等,因爲Node的特殊性,還會加入異步代碼測試和私有方法的測試;
JavaScript的斷言規範最先來自於CommonJS的單元測試規範;
單元測試風格主要有TDD(測試驅動開發)和BDD(行爲驅動開發)兩種;
BDD對測試用例的組織主要採用describe和it進行組織;
TDD對測試用例的組織主要採用suite和test完成;
單元測試覆蓋率方便咱們定位沒有測試到的代碼行;
私有方法的測試(Java一類的語言,私有方法訪問能夠經過反射的方式實現;巧妙利用閉包的訣竅,在eval()執行時,實現對模塊內部局部變量的訪問,從而能夠將局部變量導出給測試用例調用執行;)
10.2.性能測試
單元測試主要用於檢測代碼的行爲是否符合預期,性能測試的範疇比較普遍,包括負載測試、壓力測試和基準測試
基準測試
壓力測試:最經常使用的工具是ab、siege、http_load等
基準測試驅動開發
測試數據與業務數據的轉換
第十一章 產品化
11.1.項目工程化
目錄結構
構建工具:在Web應用中一般會在Makefile文件中編寫一些構建任務來幫助提高效率;合併編譯、應用打包、運行測試、清理目錄、掃描代碼等;
編碼規範:一種是文檔式的約定,一種是代碼提交時的強制檢查
代碼審查
11.2.部署流程
部署環境
部署操做
11.3.性能
幾個拆分原則:作專注的事;讓擅長的工具作擅長的事情;將模型簡化;將風險分離;
動靜分離
啓動緩存
多進程架構
讀寫分離:進行數據庫的讀寫分離,將數據庫進行主從設計
11.4.日誌
訪問日誌
異常日誌:log與info方法都將信息輸出給標準輸出process.stdout,warn與error方法則將信息輸出到標準錯誤process.stderr;console對象上有個Console屬性,它是console對象的構造函數;回調函數中產生的異常,交給全局的uncaughtException事件去捕獲;
日誌與數據庫
分割日誌
11.5.監控報警
監控:一種是業務邏輯型的監控,一種是硬件型的監控;主要指標:日誌監控、響應時間、進程監控、磁盤監控、內存監控、CPU佔用監控、CPU load監控、I/O負載、網絡監控、應用狀態監控、DNS監控;
報警的實現
監控系統的穩定性
11.6.穩定性
典型的水平擴展方式就是多進程、多機器、多機房
寫在後面
pdf書籍、筆記思惟導圖、隨書代碼打包下載地址:
https://pan.baidu.com/s/1OhLjjtfffjX3hv2_Pw7AHQ
(提取碼:9m33)
紙質書京東購買地址:
https://u.jd.com/wHmeh4
(推薦購買紙質書來學習)
相關文章
1.
[書籍精讀]《深刻淺出Node.js》精讀筆記分享
2.
精讀《深刻淺出Node.js》
3.
讀書筆記: 深刻淺出node.js
4.
[書籍精讀]《CSS世界》精讀筆記分享
5.
[書籍精讀]《React進階之路》精讀筆記分享
6.
[書籍精讀]《React Native精解與實戰》精讀筆記分享
7.
Node.js: 深入淺出Nodejs讀書筆記
8.
[書籍精讀]《你不知道的JavaScript(下卷)》精讀筆記分享
9.
[書籍精讀] 《你不知道的JavaScript(上卷)》精讀筆記分享
10.
《深刻淺出ORACLE》讀書筆記
更多相關文章...
•
RSS 閱讀器
-
RSS 教程
•
PHP MySQL 讀取數據
-
PHP教程
•
Tomcat學習筆記(史上最全tomcat學習筆記)
•
JDK13 GA發佈:5大特性解讀
相關標籤/搜索
精讀
讀書分享
讀書筆記
深刻淺出Node.js
深刻淺出
原創精讀
精讀貓說
3000字精讀
精讀源碼
Node.js
JavaScript
Redis教程
PHP教程
MyBatis教程
0
分享到微博
分享到微信
分享到QQ
每日一句
每一个你不满意的现在,都有一个你没有努力的曾经。
最新文章
1.
在windows下的虛擬機中,安裝華爲電腦的deepin操作系統
2.
強烈推薦款下載不限速解析神器
3.
【區塊鏈技術】孫宇晨:區塊鏈技術帶來金融服務的信任變革
4.
搜索引起的鏈接分析-計算網頁的重要性
5.
TiDB x 微衆銀行 | 耗時降低 58%,分佈式架構助力實現普惠金融
6.
《數字孿生體技術白皮書》重磅發佈(附完整版下載)
7.
雙十一「避坑」指南:區塊鏈電子合同爲電商交易保駕護航!
8.
區塊鏈產業,怎樣「鏈」住未來?
9.
OpenglRipper使用教程
10.
springcloud請求一次好用一次不好用zuul Name or service not known
本站公眾號
歡迎關注本站公眾號,獲取更多信息
相關文章
1.
[書籍精讀]《深刻淺出Node.js》精讀筆記分享
2.
精讀《深刻淺出Node.js》
3.
讀書筆記: 深刻淺出node.js
4.
[書籍精讀]《CSS世界》精讀筆記分享
5.
[書籍精讀]《React進階之路》精讀筆記分享
6.
[書籍精讀]《React Native精解與實戰》精讀筆記分享
7.
Node.js: 深入淺出Nodejs讀書筆記
8.
[書籍精讀]《你不知道的JavaScript(下卷)》精讀筆記分享
9.
[書籍精讀] 《你不知道的JavaScript(上卷)》精讀筆記分享
10.
《深刻淺出ORACLE》讀書筆記
>>更多相關文章<<