iT邦幫忙

2021 iThome 鐵人賽

DAY 7
0
Modern Web

NestJS 帶你飛!系列 第 7

[NestJS 帶你飛!] DAY07 - Provider (下)

  • 分享至 

  • xImage
  •  

本系列文已出版成書「NestJS 基礎必學實務指南:使用強大且易擴展的 Node.js 框架打造網頁應用程式」,感謝 iT 邦幫忙與博碩文化的協助。如果對 NestJS 有興趣、覺得這個系列文對你有幫助的話,歡迎前往購書,你的支持是我最大的寫作動力!

匯出自訂 Provider

在介紹共享模組的時候,有提到可以透過 Module 的 exports 將 Provider 匯出,那自訂 Provider 要如何匯出呢?這部分可以透過一些小技巧來達成。先建立一個 HandsomeModule 來做測試:

$ nest generate module handsome

接著,我們把 Custom Provider 的 展開式用變數儲存起來,再將該展開式放到 providersexports 中:

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

有時候可能需要等待某些非同步的操作來建立 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

有時候可能會有 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 的一些小技巧做介紹,下方為懶人包:

  1. 自訂 Provider 可以透過把展開式抽離至變數來進行匯出。
  2. Provider 支援非同步建立,在尚未建立完 Provider 以前,Nest App 不會正式啟動。
  3. 如果 Provider 並不是必須項目,必須在注入的地方添加 @Optional,這邊也建議替該參數設置預設值。

在了解完 Nest 鐵三角之後,就可以開始介紹一些其他的功能了!那就明天見囉!


上一篇
[NestJS 帶你飛!] DAY06 - Provider (上)
下一篇
[NestJS 帶你飛!] DAY08 - Exception & Exception filters
系列文
NestJS 帶你飛!32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
AndrewYEE
iT邦新手 3 級 ‧ 2022-11-08 16:23:51

想請教Service與Providor的差異,應該說providor具體定義是甚麼? 或是包含甚麼?
本章節範例中,直接在Module檔案裡寫Providor,請問這個Providor算是Service嗎?
如果基本Providor功能皆能在Module寫完並引用,那還需要Service嗎?
謝謝

HAO iT邦研究生 3 級 ‧ 2022-11-08 20:49:43 檢舉

您好,在 NestJS 的世界裡,Service 一定是 Provider,但 Provider 不一定是 Service。基本上構成 Provider 的要素是「有沒有透過 NestJS 的依賴注入機制進行管理」,所以任何物件都可以是 Provider。

至於要不要設計 Service 取決於開發者,但我通常會建議把處理商業邏輯的事情交給 Service 來做。

附註:Service 其實是一種 Architectural Pattern,會把特定邏輯放在裡面處理,不是NestJS 特有的呦。

那可能會想問自訂 Provider 要用在什麼地方?基本上在實作 Dynamic Module 就有很高的機會會使用到,或是使用第三方套件要將該套件建立的實例納入 NestJS 的依賴注入機制。還有一種使用的時機是撰寫測試,可以運用自訂 Provider 來 Mock。

AndrewYEE iT邦新手 3 級 ‧ 2022-11-09 10:29:07 檢舉

懂了~ 非常感謝您詳細說明!

我要留言

立即登入留言