來(lái)自不同語(yǔ)言背景的開(kāi)發(fā)者,在學(xué)習(xí)Nest時(shí)可能預(yù)料不到在請(qǐng)求中幾乎所有內(nèi)容都是共享的。我們建立一個(gè)連接池到數(shù)據(jù)庫(kù),在全局狀態(tài)下使用單例服務(wù)。 要記住Node.js并不遵循多線程下請(qǐng)求/響應(yīng)的無(wú)狀態(tài)模式。因此,在我們的應(yīng)用中使用單例是安全的。
然而,在需要考慮請(qǐng)求生命周期的情況下,存在邊緣情況.例如,在GraphQL應(yīng)用的預(yù)請(qǐng)求緩存中,以及請(qǐng)求追蹤和多租戶條件下,注入作用域提供了一個(gè)機(jī)制來(lái)獲取需要的提供者生命周期行為.
基本上,每個(gè)提供者都可以作為一個(gè)單例,被請(qǐng)求范圍限定,并切換到瞬態(tài)模式。請(qǐng)參見(jiàn)下表,以熟悉它們之間的區(qū)別。
DEFAULT | 每個(gè)提供者可以跨多個(gè)類共享。提供者生命周期嚴(yán)格綁定到應(yīng)用程序生命周期。一旦應(yīng)用程序啟動(dòng),所有提供程序都已實(shí)例化。默認(rèn)情況下使用單例范圍。 |
REQUEST | 在請(qǐng)求處理完成后,將為每個(gè)傳入請(qǐng)求和垃圾收集專門(mén)創(chuàng)建提供者的新實(shí)例 |
TRANSIENT | 臨時(shí)提供者不能在提供者之間共享。每當(dāng)其他提供者向 Nest 容器請(qǐng)求特定的臨時(shí)提供者時(shí),該容器將創(chuàng)建一個(gè)新的專用實(shí)例 |
使用單例范圍始終是推薦的方法。請(qǐng)求之間共享提供者可以降低內(nèi)存消耗,從而提高應(yīng)用程序的性能(不需要每次實(shí)例化類)。
為了切換到另一個(gè)注入范圍,您必須向 @Injectable() 裝飾器傳遞一個(gè)選項(xiàng)對(duì)象。
import { Injectable, Scope } from '@nestjs/common';
@Injectable({ scope: Scope.REQUEST })
export class CatsService {}
在自定義提供者的情況下,您必須設(shè)置一個(gè)額外的范圍屬性。
{
provide: 'CACHE_MANAGER',
useClass: CacheManager,
scope: Scope.TRANSIENT,
}
Scope從@nestjs/common中導(dǎo)入。
網(wǎng)關(guān)不應(yīng)該使用請(qǐng)求范圍提供者,因?yàn)槠浔仨氉鳛閱卫峁?。每個(gè)網(wǎng)關(guān)都封裝了一個(gè)socket并且不能多次實(shí)例化。
默認(rèn)使用單例范圍,并且不需要聲明。如果你想聲明一個(gè)單例范圍的提供者,在scope屬性中使用Scope.DEFAULT值。
當(dāng)涉及到控制器時(shí),傳遞 ControllerOptions 對(duì)象
@Controller({
path: 'cats',
scope: Scope.REQUEST,
})
export class CatsController {}
網(wǎng)關(guān)永遠(yuǎn)不應(yīng)該依賴于請(qǐng)求范圍的提供者,因?yàn)樗鼈兂洚?dāng)單例。一個(gè)網(wǎng)關(guān)封裝了一個(gè)真正的套接字,不能多次被實(shí)例化
必須非常謹(jǐn)慎地使用請(qǐng)求范圍的提供者。請(qǐng)記住,scope 實(shí)際上是在注入鏈中冒泡的。如果您的控制器依賴于一個(gè)請(qǐng)求范圍的提供者,這意味著您的控制器實(shí)際上也是請(qǐng)求范圍。
想象一下下面的鏈: CatsController <- CatsService <- CatsRepository 。如果您的 CatsService 是請(qǐng)求范圍的(從理論上講,其余的都是單例),那么 CatsController 也將成為請(qǐng)求范圍的(因?yàn)楸仨殞⒄?qǐng)求范圍的實(shí)例注入到新創(chuàng)建的控制器中),而 CatsRepository 仍然是單例的。
在這種情況下,循環(huán)依賴關(guān)系將導(dǎo)致非常痛苦的副作用,因此,您當(dāng)然應(yīng)該避免創(chuàng)建它們
在 HTTP 應(yīng)用程序中(例如使用@nestjs/platform-express或@nestjs/platform-fastify),當(dāng)使用請(qǐng)求范圍提供者時(shí),可能需要獲取原始的請(qǐng)求對(duì)象。這通過(guò)注入REQUEST對(duì)象實(shí)現(xiàn):
import { Injectable, Scope, Inject } from '@nestjs/common';
import { REQUEST } from '@nestjs/core';
import { Request } from 'express';
@Injectable({ scope: Scope.REQUEST })
export class CatsService {
constructor(@Inject(REQUEST) private readonly request: Request) {}
}
由于底層平臺(tái)和協(xié)議不同,該功能與微服務(wù)和 GraphQL 應(yīng)用程序略有不同。在 GraphQL 應(yīng)用程序中,可以注入 CONTEXT來(lái)替代REQUEST。
import { Injectable, Scope, Inject } from '@nestjs/common';
import { CONTEXT } from '@nestjs/graphql';
@Injectable({ scope: Scope.REQUEST })
export class CatsService {
constructor(@Inject(CONTEXT) private readonly context) {}
}
然后,您可以配置您的 context 值(在GraphQLModule中),以包含請(qǐng)求作為其屬性。
使用請(qǐng)求范圍的提供者將明顯影響應(yīng)用程序性能。即使 Nest 試圖緩存盡可能多的元數(shù)據(jù),它仍然必須為每個(gè)請(qǐng)求創(chuàng)建類的實(shí)例。因此,它將降低您的平均響應(yīng)時(shí)間和總體基準(zhǔn)測(cè)試結(jié)果。如果您的提供者不一定需要請(qǐng)求范圍,那么您應(yīng)該堅(jiān)持使用單例范圍。
更多建議: