Skip to main content

Що таке Singleton-провайдери?

Що таке Singleton-провайдер

Singleton-провайдер - це провайдер, у якого існує лише один екземпляр (instance) на весь застосунок NestJS. Коли контейнер NestJS вперше створює цей провайдер, він кешує екземпляр, і всі наступні запити до цього провайдера отримують ту саму копію.

Приклад

javascript
import { Injectable } from '@nestjs/common'; @Injectable() export class CounterService { private counter = 0; increment() { this.counter++; return this.counter; } }

І два контролери використовують цей сервіс:

javascript
import { Controller, Get } from '@nestjs/common'; import { CounterService } from './counter.service'; @Controller('a') export class AController { constructor(private readonly counterService: CounterService) {} @Get() add() { return this.counterService.increment(); } } @Controller('b') export class BController { constructor(private readonly counterService: CounterService) {} @Get() add() { return this.counterService.increment(); } }

Що відбудеться:

  • NestJS створить один спільний екземпляр CounterService;
  • обидва контролери (AController і BController) використовуватимуть той самий об'єкт;
  • значення лічильника буде спільним:
ЗапитРезультат
GET /a1створюється вперше
GET /b2використовує той самий екземпляр

Чому це зручно

  • Економія ресурсів: об'єкт створюється лише один раз.
  • Спільний state: зручно, якщо потрібно кешувати дані, тримати пул підключень тощо.
  • Простота: не потрібно вручну керувати часом життя об'єкта.

Як NestJS вирішує, що провайдер - Singleton

За замовчуванням усі провайдери в NestJS мають scope: DEFAULT, а DEFAULT = singleton.

javascript
@Injectable({ scope: Scope.DEFAULT }) // те саме, що просто @Injectable() export class MyService {}

Інші типи областей видимості (Scope)

ScopeОпис
Singleton (DEFAULT)Один екземпляр на весь застосунок (за замовчуванням)
RequestНовий екземпляр на кожен HTTP-запит
TransientНовий екземпляр при кожному впровадженні (щоразу новий об'єкт)

Приклад Request-Scoped провайдера:

javascript
import { Injectable, Scope } from '@nestjs/common'; @Injectable({ scope: Scope.REQUEST }) export class RequestService { constructor() { console.log('Новий екземпляр для запиту!'); } }

У цьому випадку при кожному HTTP-запиті Nest створюватиме новий об'єкт, а не використовуватиме спільний.

Коли Singleton-провайдер - це добре

Чудово підходить для:

  • сервісів зі спільною логікою, не залежною від запиту;
  • логування, конфігурації, роботи з БД (одне підключення);
  • кешування, токенів, сервісів, які не зберігають унікальні дані запиту.

Коли Singleton-провайдер - погана ідея

Не використовуй Singleton, якщо:

  • провайдер зберігає стан, залежний від конкретного запиту;
  • він має бути ізольований між користувачами;
  • він містить дані користувача, які не можна ділити між запитами.

У таких випадках обирають Scope.REQUEST чи Scope.TRANSIENT.

Підсумок

ПоняттяОпис
Singleton-провайдерОдин спільний екземпляр провайдера на весь застосунок
СтворюєтьсяОдин раз при ініціалізації модуля
ВикористовуєтьсяУ всіх місцях, де він впроваджений
За замовчуваннямУсі провайдери NestJS - singleton
ПеревагиШвидше, економніше, зручно для кешів, констант, БД
ОбмеженняНе підходить для залежностей, унікальних на кожен запит

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.