本系列文已出版成書「NestJS 基礎必學實務指南:使用強大且易擴展的 Node.js 框架打造網頁應用程式」,感謝 iT 邦幫忙與博碩文化的協助。如果對 NestJS 有興趣、覺得這個系列文對你有幫助的話,歡迎前往購書,你的支持是我最大的寫作動力!
在介紹共享模組的時候,有提到可以透過 Module 的 exports
將 Provider 匯出,那自訂 Provider 要如何匯出呢?這部分可以透過一些小技巧來達成。先建立一個 HandsomeModule
來做測試:
$ nest generate module handsome
接著,我們把 Custom Provider 的 展開式用變數儲存起來,再將該展開式放到 providers
與 exports
中:
import { Module } from '@nestjs/common';
const HANDSOME_HAO = {
provide: 'HANDSOME_MAN',
useValue: {
name: 'HAO'
}
};
@Module({
providers: [
HANDSOME_HAO
],
exports: [
HANDSOME_HAO
]
})
export class HandsomeModule {}
在 AppModule
進行匯入,下方為 app.module.ts
的範例:
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { HandsomeModule } from './handsome/handsome.module';
@Module({
imports: [HandsomeModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
修改 app.controller.ts
查看結果,會在終端機看到:
{ name: 'HAO' }
有時候可能需要等待某些非同步的操作來建立 Provider,比如:需要與資料庫連線,Nest App 會等待該 Provider 建立完成才正式啟動。這邊以上方的範例來做修改,調整一下 handsome.module.ts
的內容:
import { Module } from '@nestjs/common';
const HANDSOME_HAO = {
provide: 'HANDSOME_MAN',
useFactory: async () => {
const getHAO = new Promise(resolve => {
setTimeout(() => resolve({ name: 'HAO' }), 2000);
});
const HAO = await getHAO;
return HAO;
}
};
@Module({
providers: [
HANDSOME_HAO
],
exports: [
HANDSOME_HAO
]
})
export class HandsomeModule {}
在等待兩秒後,終端機會出現下方結果:
{ name: 'HAO' }
有時候可能會有 Provider 沒有被提供但卻注入的情況,這樣在啟動時會報錯,因為 Nest 找不到對應的 Provider,那遇到這種情況該如何處理呢?首先,遇到這類型情況通常會給個預設值代替沒被注入的 Provider,然後要在注入的地方添加 @Optional
裝飾器。這裡我們同樣沿用上方範例,去修改 app.module.ts
的內容,將 HandsomeModule
移除匯入:
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
接著去修改 app.controller.ts
的內容,替 HANDSOME_MAN
給定預設值:
import { Controller, Get, Inject, Optional } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(
private readonly appService: AppService,
@Optional() @Inject('HANDSOME_MAN') private readonly handsomeMan = { name: '' }
) {
console.log(this.handsomeMan);
}
@Get()
getHello(): string {
return this.appService.getHello();
}
}
此時的終端機會顯示結果:
{ name: '' }
今天的內容主要是針對 Provider 的一些小技巧做介紹,下方為懶人包:
@Optional
,這邊也建議替該參數設置預設值。在了解完 Nest 鐵三角之後,就可以開始介紹一些其他的功能了!那就明天見囉!
想請教Service與Providor的差異,應該說providor具體定義是甚麼? 或是包含甚麼?
本章節範例中,直接在Module檔案裡寫Providor,請問這個Providor算是Service嗎?
如果基本Providor功能皆能在Module寫完並引用,那還需要Service嗎?
謝謝
您好,在 NestJS 的世界裡,Service 一定是 Provider,但 Provider 不一定是 Service。基本上構成 Provider 的要素是「有沒有透過 NestJS 的依賴注入機制進行管理」,所以任何物件都可以是 Provider。
至於要不要設計 Service 取決於開發者,但我通常會建議把處理商業邏輯的事情交給 Service 來做。
附註:Service 其實是一種 Architectural Pattern,會把特定邏輯放在裡面處理,不是NestJS 特有的呦。
那可能會想問自訂 Provider 要用在什麼地方?基本上在實作 Dynamic Module 就有很高的機會會使用到,或是使用第三方套件要將該套件建立的實例納入 NestJS 的依賴注入機制。還有一種使用的時機是撰寫測試,可以運用自訂 Provider 來 Mock。
懂了~ 非常感謝您詳細說明!