本書中使用好的辦法來實現(xiàn)各種設計模式以創(chuàng)造高效且健壯的Node.js應用程序。本書首先介紹Node.js的基礎知識,包括異步事件驅動架構以及基本的設計模式。然后,介紹怎樣用callback (回調)、Promise以及async/await機制來構建異步的控制流模式。其次,介紹Node.js的stream (流)并演示stream的強大功能,使讀者能充分地利用這些功能。本書分析了三大類設計模式,即創(chuàng)建型的設計模式、結構型的設計模式以及行為型的設計模式,并介紹了怎樣在JavaScript語言及Node.js平臺中充分運用這些模式。后,書中研究了一些比較高端的概念,例如UniversalJavaScript、Node.js程序的擴展問題以及消息傳遞模式等,以幫助讀者打造企業(yè)級的分布式應用程序。
本書適合已了解Node.js技術,同時希望在程序的效率、設計及可擴展程度方面有所提高的開發(fā)者。閱讀本書需要讀者掌握Web應用程序、WebService、數(shù)據(jù)庫與數(shù)據(jù)結構方面的開發(fā)技術。
Mario Casciaro是一位軟件工程師和企業(yè)家,對技術,科學和開源知識充滿熱情。Mario畢業(yè)于軟件工程碩士學位,并開始了他在IBM的職業(yè)生涯。目前,Mario是Sponsorama.com的聯(lián)合創(chuàng)始人兼首席執(zhí)行官,該平臺通過企業(yè)贊助來幫助在線項目籌集資金,還是版Node.js設計模式的作者。Luciano Mammino是一位軟件工程師,出生于1987年。他從12歲開始使用父親的舊Intel 386(僅提供DOS操作系統(tǒng)和qBasic解釋器)進行編碼。在獲得計算機科學碩士學位之后,他主要是作為網(wǎng)絡開發(fā)人員發(fā)展了自己的編程技能,主要是為意大利各地的公司和初創(chuàng)公司擔任自由職業(yè)者。在擔任CTO和Sbaam.com在意大利和愛爾蘭的聯(lián)合創(chuàng)始人長達三年的創(chuàng)業(yè)后,在Smartbox擔任高級PHP工程師。他喜歡開發(fā)開源庫并喜歡使用Symfony和Express這樣的框架。
目錄
前言
第1章 Node.js平臺 1
1.1 Node.js開發(fā)理念 1
1.1.1 小核心 2
1.1.2 小模塊 2
1.1.3 小接觸面 (小暴露面) 3
1.1.4 簡單實用 3
1.2 Node.js的工作原理 4
1.2.1 I/O是慢速操作 4
1.2.2 阻塞式I/O 4
1.2.3 非阻塞式的I/O 5
1.2.4 事件多路分離 6
1.2.5 reactor模式 8
1.2.6 Node.js的I/O引擎Libuv 10
1.2.7 Node.js的全套結構 10
1.3 Node.js平臺之中的JavaScript 11
1.3.1 放心地使用版的JavaScript 11
1.3.2 模塊系統(tǒng) 12
1.3.3 訪問操作系統(tǒng)中的各項服務 12
1.3.4 運行原生代碼 13
1.4 小結 14
第2章 模塊系統(tǒng) 15
2.1 為什么需要模塊 15
2.2 JavaScript與Node.js的模塊系統(tǒng) 16
2.3 模塊系統(tǒng)及其模式 17
2.4 CommonJS模塊 19
2.4.1 自制的模塊加載器 19
2.4.2 定義模塊 21
2.4.3 module.exports與exports 22
2.4.4 require函數(shù)是同步函數(shù) 23
2.4.5 模塊解析算法 23
2.4.6 模塊緩存 25
2.4.7 循環(huán)依賴 26
2.5 定義模塊所用的模式 30
2.5.1 命名導出模式 30
2.5.2 函數(shù)導出模式 31
2.5.3 類導出模式 32
2.5.4 實例導出模式 33
2.5.5 通過monkeypatching模式修改其他模塊或全局作用域 34
2.6 ECMAScript模塊 (ESM) 35
2.6.1 在Node.js平臺中使用ESM 36
2.6.2 命名導出模式與命名引入 36
2.6.3 默認導出與默認引入 39
2.6.4 混用命名導出與默認導出 40
2.6.5 模塊標識符 41
2.6.6 異步引入 42
2.6.7 詳細解釋模塊的加載過程 44
2.6.8 修改其他模塊 51
2.7 ESM與CommonJS之間的區(qū)別以及交互使用技巧 55
2.7.1 ESM是在嚴格模式下運行的 55
2.7.2 ESM不支持CommonJS提供的某些引用 55
2.7.3 在其中一種模塊系統(tǒng)里面使用另一種模塊 56
2.8 小結 57
第3章 回調與事件 58
3.1 Callback (回調)模式 58
3.1.1 continuation-passing風格 (CPS) 59
3.1.2 某個函數(shù)究竟是同步函數(shù),還是異步函數(shù)? 62
3.1.3 在Node.js里面定義回調的慣例 68
3.2 Observer(觀察者)模式 72
3.2.1 EventEmitter 73
3.2.2 創(chuàng)建并使用EventEmitter 74
3.2.3 播報錯誤信息 75
3.2.4 讓任何一個對象都能為監(jiān)聽器所觀察 75
3.2.5 EventEmitter與內存泄露 77
3.2.6 同步事件與異步事件 78
3.2.7 EventEmitter與callback(回調)之間的對比 80
3.2.8 把回調與事件結合起來 81
3.3 小結 82
3.4 習題 82
第4章 利用回調實現(xiàn)異步控制流模式 84
4.1 異步編程所遇到的困難 84
4.1.1 創(chuàng)建簡單的網(wǎng)頁爬蟲 85
4.1.2 callbackhell 87
4.2 涉及回調的編程技巧與控制流模式 88
4.2.1 編寫回調邏輯時所應遵循的原則 89
4.2.2 運用相關的原則編寫回調 89
4.2.3 順序執(zhí)行 92
4.2.4 平行執(zhí)行 98
4.2.5 限制任務數(shù)量的平行執(zhí)行 104
4.3 async庫 112
4.4 小結 113
4.5 習題 113
第5章 利用Promise與async/await實現(xiàn)異步控制流模式 115
5.1 Promise 116
5.1.1 什么是Promise? 116
5.1.2 Promises/A 與thenable 119
5.1.3 PromiseAPI 119
5.1.4 創(chuàng)建Promise 121
5.1.5 把回調方案改寫成Promise方案 122
5.1.6 順序執(zhí)行與迭代 124
5.1.7 平行執(zhí)行 128
5.1.8 限制任務數(shù)量的平行執(zhí)行 129
5.2 async/await 132
5.2.1 async函數(shù)與await表達式 133
5.2.2 用async/await處理錯誤 134
5.2.3 順序執(zhí)行與迭代 137
5.2.4 平行執(zhí)行 139
5.2.5 限制任務數(shù)量的平行執(zhí)行 141
5.3 無限遞歸的Promise解析鏈所引發(fā)的問題 145
5.4 小結 148
5.5 習題 149
第6章 用Stream編程 150
6.1 理解stream在Node.js平臺中的重要作用 150
6.1.1 緩沖模式與流模式 151
6.1.2 流模式在空間占用方面的優(yōu)勢 152
6.1.3 流模式在處理時間方面的優(yōu)勢 154
6.1.4 stream之間的組合 157
6.2 開始學習Stream 160
6.2.1 流對象的體系結構 161
6.2.2 Readable流 (可讀流) 161
6.2.3 Writable流 (可寫流) 169
6.2.4 Duplex流 (雙工流/讀寫流) 175
6.2.5 Transform流 (傳輸流) 176
6.2.6 PassThrough流 183
6.2.7 lazystream (惰性流) 188
6.2.8 用管道連接流對象 189
6.3 用stream實現(xiàn)異步控制流模式 193
6.3.1 順序執(zhí)行 194
6.3.2 無序的平行執(zhí)行 196
6.3.3 無序且?guī)в胁l(fā)上限的平行執(zhí)行模式 201
6.3.4 有序的平行執(zhí)行 203
6.4 管道模式 205
6.4.1 組合stream 205
6.4.2 拆分stream (fork模式) 210
6.4.3 合并stream (merge模式) 211
6.4.4 多路復用與解多路復用 (mux/demux模式) 213
6.5 小結 220
6.6 習題 221
第7章 創(chuàng)建型的設計模式 222
7.1 Factory(工廠)模式 223
7.1.1 把對象的創(chuàng)建流程與該流程的實現(xiàn)方式解耦 223
7.1.2 強化封裝效果 225
7.1.3 構建一款簡單的codeprofiler(代碼測評工具) 226
7.1.4 Node.js大環(huán)境之中的工廠模式 229
7.2 Builder(生成器/建造者)模式 229
7.2.1 實現(xiàn)URL對象生成器 233
7.2.2 Node.js大環(huán)境之中的Builder模式 237
7.3 RevealingConstructor模式 238
7.3.1 構建不可變的緩沖區(qū) 239
7.3.2 Node.js大環(huán)境之中的RevealingConstructor模式 242
7.4 Singleton (單例/單件)模式 243
7.5 管理模塊之間的依賴關系 247
7.5.1 用Singleton模式管理模塊之間的依賴關系 247
7.5.2 用DI(依賴注入)管理模塊之間的依賴關系 250
7.6 小結 255
7.7 習題 256
第8章 結構型的設計模式 258
8.1 Proxy(代理)模式 258
8.1.1 怎樣實現(xiàn)Proxy模式 259
8.1.2 創(chuàng)建帶有日志功能的 Writable流 270
8.1.3 用Proxy實現(xiàn)ChangeObserver模式 271
8.1.4 Node.js大環(huán)境之中的Proxy模式 274
8.2 Decorator(修飾器)模式 274
8.2.1 實現(xiàn)Decorator模式的幾種辦法 275
8.2.2 用Decorator模式來修飾LevelUP數(shù)據(jù)庫 279
8.2.3 Node.js大環(huán)境之中的Decorator模式 282
8.3 Proxy模式與Decorator模式之間的區(qū)別 283
8.4 Adapter(適配器)模式 284
8.4.1 通過fs式的API來使用LevelUP 284
8.4.2 Node.js大環(huán)境之中的Adapter模式 288
8.5 小結 289
8.6 習題 290
第9章 行為型的設計模式 291
9.1 Strategy(策略)模式 292
9.1.1 處理各種格式的配置信息 293
9.1.2 Node.js大環(huán)境之中的Strategy模式 297
9.2 State(狀態(tài))模式 297
9.3 Template(模板)模式 304
9.3.1 用Template模式重新實現(xiàn)配置管理器 305
9.3.2 Node.js大環(huán)境之中的Template模式 308
9.4 Iterator(迭代器)模式 308
9.4.1 iterator協(xié)議 309
9.4.2 iterable協(xié)議 311
9.4.3 在JavaScript語言內建的機制之中使用iterator與iterable 314
9.4.4 Generator(生成器) 316
9.4.5 asynciterator(異步迭代器) 321
9.4.6 asyncgenerator(異步生成器) 324
9.4.7 asynciterator(異步迭代器)與Node.js平臺的stream (流) 325
9.4.8 Node.js大環(huán)境中的Iterator模式 326
9.5 Middleware(中間件)模式 327
9.5.1 Express里面的中間件 327
9.5.2 從模式的角度談中間件 328
9.5.3 創(chuàng)建針對ZeroMQ的中間件框架 330
9.5.4 Node.js大環(huán)境之中的 Middleware模式 337
9.6 Command(命令)模式 337
9.6.1 Task模式 339
9.6.2 用復雜一些的辦法實現(xiàn)Command 340
9.7 小結 344
9.8 習題 344
第10章 用UniversalJavaScript開發(fā) Web應用程序 347
10.1 讓Node.js與瀏覽器共用同一套代碼 348
10.2 跨平臺開發(fā)的基礎知識 360
10.2.1 在運行程序的時候做代碼分支 360
10.2.2 在構建程序的時候做代碼分支 362
10.2.3 模塊交換 (模塊替換) 365
10.2.4 適用于跨平臺開發(fā)的設計模式 366
10.3 React簡介 367
10.3.1 React編程入門 369
10.3.2 用其他寫法取代react.createElement 371
10.3.3 有狀態(tài)的Reactcomponent 373
10.4 創(chuàng)建UniversalJavaScript應用程序 379
10.4.1 先構建一款只有前端邏輯的應用程序 380
10.4.2 給程序添加服務器端的渲染邏輯 388
10.4.3 讓程序用異步的方式獲取數(shù)據(jù) 394
10.4.4 在服務器端與瀏覽器端采用同一套方案獲取數(shù)據(jù) 400
10.5 小結 415
10.6 習題 416
第11章 高級技巧 417
11.1 如何應對初始化過程中需要執(zhí)行異步任務的組件 417
11.1.1 初始化過程中含有異步任務的組件所面對的問題 418
11.1.2 預初始化隊列 (pre-initializationqueue) 420
11.1.3 Node.js大環(huán)境之中的解決方案 425
11.2 批量處理異步請求并緩存處理結果 426
11.2.1 什么叫作批量處理異步請求? 426
11.2.2 用更好的辦法來緩存異步請求的處理結果 427
11.2.3 不帶緩存或批處理機制的API服務器 428
11.2.4 利用Promise實現(xiàn)批處理與緩存 430
11.3 取消異步操作 435
11.3.1 采用基本方案創(chuàng)建可叫停的函數(shù) 435
11.3.2 把可叫停的異步函數(shù)所要執(zhí)行的異步調用包裝起來 437
11.3.3 利用生成器實現(xiàn)可叫停的異步函數(shù) 439
11.4 運行CPU密集型任務 443
11.4.1 解決subsetsum (子集合加總)問題 443
11.4.2 通過setImmediate分步執(zhí)行 447
11.4.3 使用外部進程執(zhí)行任務 450
11.4.4 用工作線程執(zhí)行任務 458
11.4.5 在實際工作中處理CPU密集型任務 462
11.5 小結 463
11.6 習題 463
第12章 用架構模式實現(xiàn)擴展 465
12.1 淺談如何擴展應用程序 466
12.1.1 擴展Node.js應用程序 466
12.1.2 從三個方面考慮可擴展能力 467
12.2 克隆與負載均衡 469
12.2.1 cluster模塊 470
12.2.2 如何處理需要根據(jù)狀態(tài)來執(zhí)行的通信請求 480
12.2.3 用反向代理擴展應用程序 483
12.2.4 動態(tài)的水平擴展 489
12.2.5 端對端的負載均衡 497
12.2.6 用容器擴展應用程序 501
12.3 分解復雜的應用程序 511
12.3.1 單體式的架構 511
12.3.2 微服務架構 513
12.3.3 適用于微服務架構的集成模式 516
12.4 小結 522
12.5 習題 523
第13章 消息傳遞與集成模式 524
13.1 消息傳遞系統(tǒng)的基礎知識 525
13.1.1 是單向通信,還是采用請求/響應模式來通信 525
13.1.2 消息的類型 526
13.1.3 異步消息傳遞機制、隊列、流 (stream) 527
13.1.4 端對端的消息傳遞與基于中介的消息傳遞 529
13.2 Publish/Subscribe(發(fā)布/訂閱)模式 530
13.2.1 構建一款極簡的實時聊天程序 531
13.2.2 用Redis充當簡單的messagebroker(消息中介) 535
13.2.3 用ZeroMQ實現(xiàn)端對端的Publish/Subscribe 538
13.2.4 用隊列確保消息可靠地得到投遞 542
13.2.5 用Stream (流)可靠地傳遞消息 552
13.3 任務分配模式 557
13.3.1 用ZeroMQ實現(xiàn)Fanout/Fanin模式 558
13.3.2 根據(jù)AMQP協(xié)議制作管道并實現(xiàn)CompetingConsumers
(互相競爭的消費者)模式 567
13.3.3 用Redis流實現(xiàn)任務分配模式 571
13.4 Request/Reply(請求/響應)模式 577
13.4.1 關聯(lián)標識符 577
13.4.2 ReturnAddress(返回地址)模式 584
13.5 小結 591
13.6 習題 591