本書中使用好的辦法來實(shí)現(xiàn)各種設(shè)計模式以創(chuàng)造高效且健壯的Node.js應(yīng)用程序。本書首先介紹Node.js的基礎(chǔ)知識,包括異步事件驅(qū)動架構(gòu)以及基本的設(shè)計模式。然后,介紹怎樣用callback (回調(diào))、Promise以及async/await機(jī)制來構(gòu)建異步的控制流模式。其次,介紹Node.js的stream (流)并演示stream的強(qiáng)大功能,使讀者能充分地利用這些功能。本書分析了三大類設(shè)計模式,即創(chuàng)建型的設(shè)計模式、結(jié)構(gòu)型的設(shè)計模式以及行為型的設(shè)計模式,并介紹了怎樣在JavaScript語言及Node.js平臺中充分運(yùn)用這些模式。后,書中研究了一些比較高端的概念,例如UniversalJavaScript、Node.js程序的擴(kuò)展問題以及消息傳遞模式等,以幫助讀者打造企業(yè)級的分布式應(yīng)用程序。
本書適合已了解Node.js技術(shù),同時希望在程序的效率、設(shè)計及可擴(kuò)展程度方面有所提高的開發(fā)者。閱讀本書需要讀者掌握Web應(yīng)用程序、WebService、數(shù)據(jù)庫與數(shù)據(jù)結(jié)構(gòu)方面的開發(fā)技術(shù)。
Mario Casciaro是一位軟件工程師和企業(yè)家,對技術(shù),科學(xué)和開源知識充滿熱情。Mario畢業(yè)于軟件工程碩士學(xué)位,并開始了他在IBM的職業(yè)生涯。目前,Mario是Sponsorama.com的聯(lián)合創(chuàng)始人兼首席執(zhí)行官,該平臺通過企業(yè)贊助來幫助在線項目籌集資金,還是版Node.js設(shè)計模式的作者。Luciano Mammino是一位軟件工程師,出生于1987年。他從12歲開始使用父親的舊Intel 386(僅提供DOS操作系統(tǒng)和qBasic解釋器)進(jìn)行編碼。在獲得計算機(jī)科學(xué)碩士學(xué)位之后,他主要是作為網(wǎng)絡(luò)開發(fā)人員發(fā)展了自己的編程技能,主要是為意大利各地的公司和初創(chuàng)公司擔(dān)任自由職業(yè)者。在擔(dān)任CTO和Sbaam.com在意大利和愛爾蘭的聯(lián)合創(chuàng)始人長達(dá)三年的創(chuàng)業(yè)后,在Smartbox擔(dān)任高級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 簡單實(shí)用 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的全套結(jié)構(gòu) 10
1.3 Node.js平臺之中的JavaScript 11
1.3.1 放心地使用版的JavaScript 11
1.3.2 模塊系統(tǒng) 12
1.3.3 訪問操作系統(tǒng)中的各項服務(wù) 12
1.3.4 運(yùn)行原生代碼 13
1.4 小結(jié) 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 命名導(dǎo)出模式 30
2.5.2 函數(shù)導(dǎo)出模式 31
2.5.3 類導(dǎo)出模式 32
2.5.4 實(shí)例導(dǎo)出模式 33
2.5.5 通過monkeypatching模式修改其他模塊或全局作用域 34
2.6 ECMAScript模塊 (ESM) 35
2.6.1 在Node.js平臺中使用ESM 36
2.6.2 命名導(dǎo)出模式與命名引入 36
2.6.3 默認(rèn)導(dǎo)出與默認(rèn)引入 39
2.6.4 混用命名導(dǎo)出與默認(rèn)導(dǎo)出 40
2.6.5 模塊標(biāo)識符 41
2.6.6 異步引入 42
2.6.7 詳細(xì)解釋模塊的加載過程 44
2.6.8 修改其他模塊 51
2.7 ESM與CommonJS之間的區(qū)別以及交互使用技巧 55
2.7.1 ESM是在嚴(yán)格模式下運(yùn)行的 55
2.7.2 ESM不支持CommonJS提供的某些引用 55
2.7.3 在其中一種模塊系統(tǒng)里面使用另一種模塊 56
2.8 小結(jié) 57
第3章 回調(diào)與事件 58
3.1 Callback (回調(diào))模式 58
3.1.1 continuation-passing風(fēng)格 (CPS) 59
3.1.2 某個函數(shù)究竟是同步函數(shù),還是異步函數(shù)? 62
3.1.3 在Node.js里面定義回調(diào)的慣例 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與內(nèi)存泄露 77
3.2.6 同步事件與異步事件 78
3.2.7 EventEmitter與callback(回調(diào))之間的對比 80
3.2.8 把回調(diào)與事件結(jié)合起來 81
3.3 小結(jié) 82
3.4 習(xí)題 82
第4章 利用回調(diào)實(shí)現(xiàn)異步控制流模式 84
4.1 異步編程所遇到的困難 84
4.1.1 創(chuàng)建簡單的網(wǎng)頁爬蟲 85
4.1.2 callbackhell 87
4.2 涉及回調(diào)的編程技巧與控制流模式 88
4.2.1 編寫回調(diào)邏輯時所應(yīng)遵循的原則 89
4.2.2 運(yùn)用相關(guān)的原則編寫回調(diào) 89
4.2.3 順序執(zhí)行 92
4.2.4 平行執(zhí)行 98
4.2.5 限制任務(wù)數(shù)量的平行執(zhí)行 104
4.3 async庫 112
4.4 小結(jié) 113
4.5 習(xí)題 113
第5章 利用Promise與async/await實(shí)現(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 把回調(diào)方案改寫成Promise方案 122
5.1.6 順序執(zhí)行與迭代 124
5.1.7 平行執(zhí)行 128
5.1.8 限制任務(wù)數(shù)量的平行執(zhí)行 129
5.2 async/await 132
5.2.1 async函數(shù)與await表達(dá)式 133
5.2.2 用async/await處理錯誤 134
5.2.3 順序執(zhí)行與迭代 137
5.2.4 平行執(zhí)行 139
5.2.5 限制任務(wù)數(shù)量的平行執(zhí)行 141
5.3 無限遞歸的Promise解析鏈所引發(fā)的問題 145
5.4 小結(jié) 148
5.5 習(xí)題 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 開始學(xué)習(xí)Stream 160
6.2.1 流對象的體系結(jié)構(gòu) 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實(shí)現(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 多路復(fù)用與解多路復(fù)用 (mux/demux模式) 213
6.5 小結(jié) 220
6.6 習(xí)題 221
第7章 創(chuàng)建型的設(shè)計模式 222
7.1 Factory(工廠)模式 223
7.1.1 把對象的創(chuàng)建流程與該流程的實(shí)現(xiàn)方式解耦 223
7.1.2 強(qiáng)化封裝效果 225
7.1.3 構(gòu)建一款簡單的codeprofiler(代碼測評工具) 226
7.1.4 Node.js大環(huán)境之中的工廠模式 229
7.2 Builder(生成器/建造者)模式 229
7.2.1 實(shí)現(xiàn)URL對象生成器 233
7.2.2 Node.js大環(huán)境之中的Builder模式 237
7.3 RevealingConstructor模式 238
7.3.1 構(gòu)建不可變的緩沖區(qū) 239
7.3.2 Node.js大環(huán)境之中的RevealingConstructor模式 242
7.4 Singleton (單例/單件)模式 243
7.5 管理模塊之間的依賴關(guān)系 247
7.5.1 用Singleton模式管理模塊之間的依賴關(guān)系 247
7.5.2 用DI(依賴注入)管理模塊之間的依賴關(guān)系 250
7.6 小結(jié) 255
7.7 習(xí)題 256
第8章 結(jié)構(gòu)型的設(shè)計模式 258
8.1 Proxy(代理)模式 258
8.1.1 怎樣實(shí)現(xiàn)Proxy模式 259
8.1.2 創(chuàng)建帶有日志功能的 Writable流 270
8.1.3 用Proxy實(shí)現(xiàn)ChangeObserver模式 271
8.1.4 Node.js大環(huán)境之中的Proxy模式 274
8.2 Decorator(修飾器)模式 274
8.2.1 實(shí)現(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 小結(jié) 289
8.6 習(xí)題 290
第9章 行為型的設(shè)計模式 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模式重新實(shí)現(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語言內(nèi)建的機(jī)制之中使用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 用復(fù)雜一些的辦法實(shí)現(xiàn)Command 340
9.7 小結(jié) 344
9.8 習(xí)題 344
第10章 用UniversalJavaScript開發(fā) Web應(yīng)用程序 347
10.1 讓Node.js與瀏覽器共用同一套代碼 348
10.2 跨平臺開發(fā)的基礎(chǔ)知識 360
10.2.1 在運(yùn)行程序的時候做代碼分支 360
10.2.2 在構(gòu)建程序的時候做代碼分支 362
10.2.3 模塊交換 (模塊替換) 365
10.2.4 適用于跨平臺開發(fā)的設(shè)計模式 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應(yīng)用程序 379
10.4.1 先構(gòu)建一款只有前端邏輯的應(yīng)用程序 380
10.4.2 給程序添加服務(wù)器端的渲染邏輯 388
10.4.3 讓程序用異步的方式獲取數(shù)據(jù) 394
10.4.4 在服務(wù)器端與瀏覽器端采用同一套方案獲取數(shù)據(jù) 400
10.5 小結(jié) 415
10.6 習(xí)題 416
第11章 高級技巧 417
11.1 如何應(yīng)對初始化過程中需要執(zhí)行異步任務(wù)的組件 417
11.1.1 初始化過程中含有異步任務(wù)的組件所面對的問題 418
11.1.2 預(yù)初始化隊列 (pre-initializationqueue) 420
11.1.3 Node.js大環(huán)境之中的解決方案 425
11.2 批量處理異步請求并緩存處理結(jié)果 426
11.2.1 什么叫作批量處理異步請求? 426
11.2.2 用更好的辦法來緩存異步請求的處理結(jié)果 427
11.2.3 不帶緩存或批處理機(jī)制的API服務(wù)器 428
11.2.4 利用Promise實(shí)現(xiàn)批處理與緩存 430
11.3 取消異步操作 435
11.3.1 采用基本方案創(chuàng)建可叫停的函數(shù) 435
11.3.2 把可叫停的異步函數(shù)所要執(zhí)行的異步調(diào)用包裝起來 437
11.3.3 利用生成器實(shí)現(xiàn)可叫停的異步函數(shù) 439
11.4 運(yùn)行CPU密集型任務(wù) 443
11.4.1 解決subsetsum (子集合加總)問題 443
11.4.2 通過setImmediate分步執(zhí)行 447
11.4.3 使用外部進(jìn)程執(zhí)行任務(wù) 450
11.4.4 用工作線程執(zhí)行任務(wù) 458
11.4.5 在實(shí)際工作中處理CPU密集型任務(wù) 462
11.5 小結(jié) 463
11.6 習(xí)題 463
第12章 用架構(gòu)模式實(shí)現(xiàn)擴(kuò)展 465
12.1 淺談如何擴(kuò)展應(yīng)用程序 466
12.1.1 擴(kuò)展Node.js應(yīng)用程序 466
12.1.2 從三個方面考慮可擴(kuò)展能力 467
12.2 克隆與負(fù)載均衡 469
12.2.1 cluster模塊 470
12.2.2 如何處理需要根據(jù)狀態(tài)來執(zhí)行的通信請求 480
12.2.3 用反向代理擴(kuò)展應(yīng)用程序 483
12.2.4 動態(tài)的水平擴(kuò)展 489
12.2.5 端對端的負(fù)載均衡 497
12.2.6 用容器擴(kuò)展應(yīng)用程序 501
12.3 分解復(fù)雜的應(yīng)用程序 511
12.3.1 單體式的架構(gòu) 511
12.3.2 微服務(wù)架構(gòu) 513
12.3.3 適用于微服務(wù)架構(gòu)的集成模式 516
12.4 小結(jié) 522
12.5 習(xí)題 523
第13章 消息傳遞與集成模式 524
13.1 消息傳遞系統(tǒng)的基礎(chǔ)知識 525
13.1.1 是單向通信,還是采用請求/響應(yīng)模式來通信 525
13.1.2 消息的類型 526
13.1.3 異步消息傳遞機(jī)制、隊列、流 (stream) 527
13.1.4 端對端的消息傳遞與基于中介的消息傳遞 529
13.2 Publish/Subscribe(發(fā)布/訂閱)模式 530
13.2.1 構(gòu)建一款極簡的實(shí)時聊天程序 531
13.2.2 用Redis充當(dāng)簡單的messagebroker(消息中介) 535
13.2.3 用ZeroMQ實(shí)現(xiàn)端對端的Publish/Subscribe 538
13.2.4 用隊列確保消息可靠地得到投遞 542
13.2.5 用Stream (流)可靠地傳遞消息 552
13.3 任務(wù)分配模式 557
13.3.1 用ZeroMQ實(shí)現(xiàn)Fanout/Fanin模式 558
13.3.2 根據(jù)AMQP協(xié)議制作管道并實(shí)現(xiàn)CompetingConsumers
(互相競爭的消費(fèi)者)模式 567
13.3.3 用Redis流實(shí)現(xiàn)任務(wù)分配模式 571
13.4 Request/Reply(請求/響應(yīng))模式 577
13.4.1 關(guān)聯(lián)標(biāo)識符 577
13.4.2 ReturnAddress(返回地址)模式 584
13.5 小結(jié) 591
13.6 習(xí)題 591