了解Node.js Nestjs框架的模塊機制,聊聊實現原理

本篇文章帶大家了解一下Node 后端框架Nest.js , 介紹一下Nestjs模塊機制的概念和實現原理 , 希望對大家有所幫助!

了解Node.js Nestjs框架的模塊機制,聊聊實現原理

文章插圖

Nest 提供了模塊機制 , 通過在模塊裝飾器中定義提供者、導入、導出和提供者構造函數便完成了依賴注入 , 通過模塊樹組織整個應用程序的開發 。 按照框架本身的約定直接擼一個應用程序 , 是完全沒有問題的 。 可是 , 于我而言對于框架宣稱的依賴注入、控制反轉、模塊、提供者、元數據、相關裝飾器等等 , 覺得缺乏一個更清晰系統的認識 。
    為什么需要控制反轉?什么是依賴注入?裝飾器做了啥?模塊 (@Module) 中的提供者(providers) , 導入(imports)、導出(exports)是什么實現原理?
好像能夠理解 , 能夠意會 , 但是讓我自己從頭說清楚 , 我說不清楚 。 于是進行了一番探索 , 便有了這篇文章 。 從現在起 , 我們從新出發 , 進入正文 。
1 兩個階段1.1 Express、Koa
一個語言和其技術社區的發展過程 , 一定是從底層功能逐漸往上豐富發展的 , 就像是樹根慢慢生長為樹枝再長滿樹葉的過程 。 在較早 , Nodejs 出現了 Express 和 Koa 這樣的基本 Web 服務框架 。 能夠提供一個非?;A的服務能力 。 基于這樣的框架 , 大量的中間件、插件開始在社區誕生 , 為框架提供更加豐富的服務 。 我們需要自己去組織應用依賴 , 搭建應用腳手架 , 靈活又繁瑣 , 也具有一定工作量 。
發展到后面 , 一些生產更高效、規則更統一的框架便誕生了 , 開啟了一個更新的階段 。
1.2 EggJs、Nestjs
為了更加適應快速生產應用 , 統一規范 , 開箱即用 , 便發展出了 EggJs、NestJs、Midway等框架 。 此類框架 , 通過實現底層生命周期 , 將一個應用的實現抽象為一個通用可擴展的過程 , 我們只需要按照框架提供的配置方式 , 便可以更簡單的實現應用程序 。 框架實現了程序的過程控制 , 而我們只需要在合適位置組裝我們的零件就行 , 這看起來更像是流水線工作 , 每個流程被分割的很清楚 , 也省去了很多實現成本 。
1.3 小結
上面的兩個階段只是一個鋪墊 , 我們可以大致了解到 , 框架的升級是提高了生產效率 , 而要實現框架的升級 , 就會引入一些設計思路和模式 , Nest 中就出現了控制反轉、依賴注入、元編程的概念 , 下面我們來聊聊 。
2 控制反轉和依賴注入2.1 依賴注入
一個應用程序實際就是非常多的抽象類 , 通過互相調用實現應用的所有功能 。 隨著應用代碼和功能復雜度的增加 , 項目一定會越來越難以維護 , 因為類越來越多 , 相互之間的關系越來越復雜 。
舉個例子 , 假如我們使用 Koa 開發我們的應用 , Koa 本身主要實現了一套基礎的 Web 服務能力 , 我們在實現應用的過程中 , 會定義很多類 , 這些類的實例化方式、相互依賴關系 , 都會由我們在代碼邏輯自由組織和控制 。 每個類的實例化都是由我們手動 new , 并且我們可以控制某個類是只實例化一次然后被共享 , 還是每次都實例化 。 下面的 B 類依賴 A , 每次實例化 B 的時候 , A 都會被實例化一次 , 所以對于每個實例 B 來說 , A 是不被共享的實例 。
class A{}// Bclass B{ contructor(){ this.a = new A(); }}下面的 C 是獲取的外部實例 , 所以多個 C 實例是共享的 app.a 這個實例 。
class A{}// Cconst app = {};app.a = new A();class C{ contructor(){ this.a = app.a; }}下面的 D 是通過構造函數參數傳入 , 可以每次傳入一個非共享實例 , 也可以傳入共享的 app.a 這個實例(D 和 F 共享 app.a) , 并且由于現在是參數的方式傳入 , 我也可以傳入一個 X 類實例 。
class A{}class X{}// Dconst app = {};app.a = new A();class D{ contructor(a){ this.a = a; }}class F{ contructor(a){ this.a = a; }}new D(app.a)new F(app.a)new D(new X())這種方式就是依賴注入 , 把 B 所依賴的 A , 通過傳值的方式注入到 B 中 。 通過構造函數注入(傳值)只是一種實現方式 , 也可以通過實現 set 方法調用傳入 , 或者是其他任何方式 , 只要能把外部的一個依賴 , 傳入到內部就行 。 其實就這么簡單 。
class A{}// Dclass D{ setDep(a){ this.a = a; }}const d = new D()d.setDep(new A())2.2 All in 依賴注入?
隨著迭代進行 , 出現了 B 根據不同的前置條件依賴會發生變化 。 比如 , 前置條件一 this.a 需要傳入 A 的實例 , 前置條件二this.a需要傳入 X 的實例 。 這個時候 , 我們就會開始做實際的抽象了 。 我們就會改造成上面 D 這樣依賴注入的方式 。

推薦閱讀