Node.js 先後端分離開發新思路

從事 Web 開發的程序員,對於先後端分離模式多半不陌生,這也是目前主流的 Web 開發模式,具體關於先後端分離的模式能夠參看文章《你不得不瞭解的先後端分離原理!》,在這裏寫者不進行說明。html

好了,讓咱們進入主題 —— Node.js 先後端分離開發新思路
在進入新思路以前,咱們現須要瞭解「老思路」是什麼?(注意:後面的案例都是以全棧工程師爲例,即先後端代碼在一塊兒)前端

先後端分離開發常規思路

以一種具體情景爲例:小牛是一名全棧工程師,喜歡前端後端全乾,前端使用目前主流的 Webpack + React 全家桶(或 Vue 全家桶),後端使用 express(或 Koa),小牛在同時開發先後端過程當中,開啓兩個進程(先後端各一個),同時使用 nodemon 熱重啓後臺服務,使用 Webpack Proxy 轉發實現跨域請求,而後哼哧哼哧開發。
如例子:一個先後端分離的簡單案例node

Process 1                Process 2
 ___________          ____________________
|           | Proxy  |          |         |
| FrontEnd  | <----> | Nodemon  | BackEnd |
|           |        |          | (cp 1)  |
-------------        ----------------------

如上示意,該模式啓動須要啓動兩個進程(前端 和 Nodemon),其中 BackEnd 程序做爲子進程掛載在 Nodemon 進程,並且前端和 Nodemon 進程經過 Proxy 轉發實現通訊。webpack

乍看一下這樣挺美好的,可是這種模式的缺陷也很容易暴露出來git

傳統思路的缺陷

  1. BackEnd 程序複雜度提高後,啓動時間也變得不可控,每次熱啓動後臺服務時間過長;
  2. 須要同時開啓兩個進程,必定程度提升了開發成本

那麼對於上述的問題,須要介紹一下咱們今天的主角!程序員

先後端分離開發新思路

依舊是小牛的例子,大牛一樣使用小牛相同的先後端技術棧,但不一樣的是,大牛不使用 Nodemon 實現後端程序的熱重啓,而是使用相似 Webpack HMR(Hot Module Replacement) 的思路,熱更新 Node.js 中的 module,具體實現使用 hot-module-requiregithub

原理圖以下,先後端在一個進程(同一個端口)中,經過 Fs Watcher 熱替換更新的 Module,而不是全量重啓。web

Process
 _________________________
|          | File Watcher |
| Frontend |       +      |
|          |    Backend   |
---------------------------

其中核心的 Node.js 端 HMR 實現思路以下算法

Node.js 端 HMR 實現思路

首先咱們來看看一個程序的依賴圖關係
express

  1. 獲得程序依賴圖
    index.js 爲程序入口,能夠經過靜態代碼分析,獲得 index.js 的直接依賴 express/index.jslib/middleware.js,而後遞歸地進行,依次獲得一個完整的依賴圖,算法具體實現參看 detect-dep
  2. 監聽依賴圖中涉及到的文件
    須要熱更新,那就離不開文件改動的監聽,因此進行依賴圖中文件的監聽(實際上只須要監聽本地的文件,排除 node builtin modules 和第三方模塊)
  3. 某個時候,lib/to-array.js 文件發生改動!

    1. 刪除更新模塊 A 緩存 (delete require.caches[modulePath])
    2. 以 A 爲入口,更新依賴圖
    3. 發出 A 更新的信號
    4. 根據依賴圖,獲得依賴 A 的模塊集合 B
    5. 向上回溯 B,再次從 0. 開始執行

其中這一步須要注意環狀依賴的處理,須要保證一條依賴路徑,不進行重複的依賴更新。
lib/to-array.js,存在兩條路徑:lib/to-array.js -> lib/middleware.js -> index/jslib/to-array.js -> lib/express-utils.js -> lib/middleware.js -> index/js

以上算法的具體實現參看 hot-module-require
具體的應用代碼能夠參看這裏

相比與傳統模式,新思路的優勢十分突出。

優點

  1. 細化 Module 更新的顆粒度,避免沒必要要的更新開銷,大大縮減服務更新時間
  2. 只有一個進程,必定程度上縮減了進程調度,進程切換的開銷

用一個具體的場景對比舉例,如後端使用內存存儲用戶 session 數據。如使用傳統方式開發,則每一次更新後臺代碼,都會丟失內存中的用戶數據,因此每次都須要從新進行登陸;可是在新方式,只須要不修改用戶登陸模塊代碼,則不會重置用戶 session 數據,即不需從新登陸。

Backend 入口
  /                \
 -                   -
登陸 --> Common <-- 某業務邏輯

如上簡易模塊依賴圖,A -> B 表示 A 依賴 B,因此上圖中,Backend 入口直接依賴 「登陸」和「某業務邏輯」,間接依賴「Common」;這時候咱們只有在修改了「登陸」或「Common」的代碼,纔會觸發登陸模塊的熱更新。

可是新方法也不是完好陷

缺陷

  1. 如代碼模塊中包含全局反作用代碼,可能會有各類奇怪問題出現

擴展

使用 Node.js HMR 能夠實現各類各樣的熱更新體驗,如熱更新 proxy,熱更新 mock 數據,熱更新配置文件...,很是 Cool!

相關材料

相關文章
相關標籤/搜索