Circular Dependency là gì ? 3 cách để giải quyết các circular dependency

0 0 0

Người đăng: Trần Nhật Sang

Theo Viblo Asia

Thêm một khái niệm fundamental nữa lấy ra từ docs của nestjs.com, đây là một khái niệm cũng thường xuyên được hỏi trong các cuộc phỏng vấn NestJS mà mình đã từng gặp. Chính vì vậy hôm nay mình quyết định lên một bài viết nói về khái niệm này. Tham khảo khái niệm circular dependency này của mình nhé

Hiểu về Circular Dependency trong NestJS

Trong NestJS, circular dependency (phụ thuộc vòng tròn) xảy ra khi hai hoặc nhiều module hoặc provider phụ thuộc vào nhau, tạo thành một vòng lặp. Ví dụ:

  • Module A phụ thuộc vào Module B.
  • Module B lại phụ thuộc vào Module A.

Điều này có thể dẫn đến các vấn đề như lỗi runtime hoặc hành vi không mong muốn vì NestJS không thể giải quyết các phụ thuộc đúng cách.


Ví dụ về Circular Dependency

Dưới đây là một ví dụ về circular dependency giữa hai service:

service-a.service.ts


import { Injectable } from '@nestjs/common';
import { ServiceB } from './service-b.service'; @Injectable()
export class ServiceA { constructor(private readonly serviceB: ServiceB) {} getMessageFromB(): string { return this.serviceB.getMessage(); }
} 

service-b.service.ts


import { Injectable } from '@nestjs/common';
import { ServiceA } from './service-a.service'; @Injectable()
export class ServiceB { constructor(private readonly serviceA: ServiceA) {} getMessage(): string { return `Hello from ServiceB. Called by: ${this.serviceA.getMessageFromB()}`; }
} 

Ở đây, cả ServiceAServiceB đều phụ thuộc lẫn nhau, tạo ra circular dependency.


Lỗi Thường Gặp

Khi chạy đoạn mã trên, NestJS sẽ báo lỗi tương tự như sau:

Error: A circular dependency has been detected (ServiceA -> ServiceB -> ServiceA).


Các Giải Pháp Giải Quyết Circular Dependency

1. Sử dụng forwardRef

NestJS cung cấp hàm forwardRef để xử lý circular dependency.

Chỉnh sửa cách import trong cả hai service như sau:

service-a.service.ts

import { Injectable, forwardRef, Inject } from '@nestjs/common';
import { ServiceB } from './service-b.service'; @Injectable()
export class ServiceA { constructor(@Inject(forwardRef(() => ServiceB)) private readonly serviceB: ServiceB) {} getMessageFromB(): string { return this.serviceB.getMessage(); }
} 
service-b.service.ts

import { Injectable, forwardRef, Inject } from '@nestjs/common';
import { ServiceA } from './service-a.service'; @Injectable()
export class ServiceB { constructor(@Inject(forwardRef(() => ServiceA)) private readonly serviceA: ServiceA) {} getMessage(): string { return `Hello from ServiceB. Called by: ${this.serviceA.getMessageFromB()}`; }
} 

2. Tái cấu trúc code để tránh Circular Dependency

Thay vì để các service phụ thuộc trực tiếp vào nhau, bạn có thể thêm một service trung gian (Mediator) để xử lý tương tác.

Tạo mediator.service.ts

import { Injectable } from '@nestjs/common'; @Injectable()
export class MediatorService { getSharedMessage(): string { return 'Shared Message'; }
} 

Cập nhật service-a.service.ts


import { Injectable } from '@nestjs/common';
import { MediatorService } from './mediator.service'; @Injectable()
export class ServiceA { constructor(private readonly mediatorService: MediatorService) {} getMessageFromMediator(): string { return this.mediatorService.getSharedMessage(); }
} 

Cập nhật service-b.service.ts


import { Injectable } from '@nestjs/common';
import { MediatorService } from './mediator.service'; @Injectable()
export class ServiceB { constructor(private readonly mediatorService: MediatorService) {} getMessageFromMediator(): string { return this.mediatorService.getSharedMessage(); }
} 

3. Tổ chức lại cấu trúc module

Nếu circular dependency xuất phát từ việc các module import lẫn nhau, hãy xem xét tổ chức lại module. Đưa logic dùng chung vào một module riêng để cả hai module cùng phụ thuộc.


Tóm tắt

  • Sử dụng forwardRef là cách xử lý nhanh chóng, nhưng không nên lạm dụng vì có thể làm phức tạp thiết kế.
  • Cách tốt nhất là tái cấu trúc code để tránh phụ thuộc vòng tròn hoàn toàn.
  • Xem xét sử dụng mediator hoặc tổ chức lại module để quản lý phụ thuộc một cách rõ ràng hơn.

Liên quan

https://docs.nestjs.com/fundamentals/circular-dependency https://chatgpt.com/share/676f69d7-0150-8013-85b0-78a8b829e0a1 Tham khảo đoạn code github của mình dùng để giải quyết circular dependency https://github.com/sangtrandev00/circular-dependency-nestjs Tham khảo thêm các khái niệm fundamental trong series NestJS cơ bản. Tham khảo bài viết gốc của mình tại đây! https://trannhatsang.com/circular-dependency-la-gi-3-cach-giai-quyet/

#nestjs #backend

Bình luận

Bài viết tương tự

- vừa được xem lúc

Tìm hiểu về NestJS (Phần 2)

Trong bài viết trước, mình đã giới thiệu về NestJS và các thành phần cơ bản của framework này cũng như xây dựng demo một api bằng NestJS. Như mình đã giới thiệu, NestJS có một hệ sinh thái hỗ trợ cho chúng ta trong quá trình phát triển mà các framework khác như Express, Fastify,... phải tự build hoặ

0 0 171

- vừa được xem lúc

NestJS - tìm hiểu và sử dụng Pipes

I. Giới thiệu.

0 0 39

- vừa được xem lúc

Authentication Với NestJS và Passport (Phần 1)

Authentication, hay xác thực thông tin người dùng, là một trong những tính năng cơ bản nhất của phần lớn ứng dụng Web. Trong bài viết này, mình xin chia sẻ phương pháp sử dụng passportjs để xây dựng t

0 0 95

- vừa được xem lúc

Authentication Với NestJS và Passport (Phần 2)

I. Giới thiệu.

0 0 174

- vừa được xem lúc

Middleware, Interceptor and Pipes in Nestjs

Middleware, Interceptor và Pipes củng không quá xa lạ với những anh em code Nestjs.Nhưng ai trong.

0 0 172

- vừa được xem lúc

NestJS - framework thần thánh cho Nodejs

Đọc thì có vẻ giật tít nhưng khoan, mọi chuyện không như bạn nghĩ, hãy nghe mình giải thích . 1.

0 0 59