angular的循環(huán)依賴和InjectionToken,怎么解決循環(huán)依賴

在 Angular 開發(fā)中,循環(huán)依賴是一個常見且棘手的問題,而?InjectionToken?是解決循環(huán)依賴的有效手段之一。下面詳細介紹 Angular 中的循環(huán)依賴問題以及如何使用?InjectionToken?來解決它。

1. 什么是循環(huán)依賴

循環(huán)依賴指的是兩個或多個服務之間相互依賴,形成一個閉環(huán)。例如,服務 A 依賴于服務 B,而服務 B 又依賴于服務 A,這樣在創(chuàng)建這些服務的實例時,就會陷入無限循環(huán),導致程序無法正常運行。

以下是一個簡單的循環(huán)依賴示例:

import { Injectable } from '@angular/core';

@Injectable({

? providedIn: 'root'

})

export class ServiceA {

? constructor(private serviceB: ServiceB) {}

}

@Injectable({

? providedIn: 'root'

})

export class ServiceB {

? constructor(private serviceA: ServiceA) {}

}

在上述代碼中,ServiceA?的構造函數依賴于?ServiceB,而?ServiceB?的構造函數又依賴于?ServiceA,這就形成了循環(huán)依賴。當 Angular 嘗試創(chuàng)建?ServiceA?的實例時,需要先創(chuàng)建?ServiceB?的實例,而創(chuàng)建?ServiceB?的實例又需要先創(chuàng)建?ServiceA?的實例,從而陷入無限循環(huán)。

2.?InjectionToken?介紹

InjectionToken?是 Angular 提供的一種機制,用于創(chuàng)建唯一的令牌,它可以作為依賴注入的標識符。與直接使用類名作為依賴注入的令牌不同,InjectionToken?可以避免命名沖突,并且可以用于注入非類的依賴項,如配置對象、常量等。

InjectionToken?的創(chuàng)建方式如下:

import { InjectionToken } from '@angular/core';

export const MY_TOKEN = new InjectionToken<string>('MY_TOKEN');

這里創(chuàng)建了一個名為?MY_TOKEN?的?InjectionToken,它的泛型參數指定了該令牌所代表的依賴項的類型,這里是?string?類型。

3. 使用?InjectionToken?解決循環(huán)依賴

下面通過一個示例來展示如何使用?InjectionToken?解決循環(huán)依賴問題。假設我們有兩個服務?ServiceA?和?ServiceB,它們之間存在循環(huán)依賴,我們可以使用?InjectionToken?來打破這個循環(huán)。

import { Injectable, Inject, InjectionToken } from '@angular/core';

// 創(chuàng)建一個 InjectionToken 用于標識原始的 ServiceB

export const ORIGINAL_SERVICE_B = new InjectionToken<ServiceB>('ORIGINAL_SERVICE_B');

@Injectable({

? providedIn: 'root'

})

export class ServiceA {

? constructor(@Inject(ORIGINAL_SERVICE_B) private serviceB: ServiceB) {}

}

@Injectable({

? providedIn: 'root'

})

export class ServiceB {

? constructor(private serviceA: ServiceA) {}

}

然后在模塊的?providers?數組中進行配置:

import { NgModule } from '@angular/core';

import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';

import { ServiceA, ServiceB, ORIGINAL_SERVICE_B } from './your-services-file';

@NgModule({

? declarations: [AppComponent],

? imports: [BrowserModule],

? providers: [

? ? { provide: ORIGINAL_SERVICE_B, useClass: ServiceB },

? ? { provide: ServiceB, useClass: ServiceB } // 這里可以根據需要替換為擴展后的 ServiceB

? ],

? bootstrap: [AppComponent]

})

export class AppModule {}

代碼解釋

創(chuàng)建?InjectionToken:ORIGINAL_SERVICE_B?是一個?InjectionToken,用于標識原始的?ServiceB。

修改?ServiceA?的構造函數:在?ServiceA?的構造函數中,使用?@Inject(ORIGINAL_SERVICE_B)?注入?ServiceB?的實例,這樣就避免了直接使用?ServiceB?類名,從而打破了循環(huán)依賴。

模塊配置:在?AppModule?的?providers?數組中,將?ORIGINAL_SERVICE_B?與?ServiceB?類關聯(lián)起來,當請求?ORIGINAL_SERVICE_B?時,Angular 會創(chuàng)建一個?ServiceB?的實例。同時,也可以根據需要將?ServiceB?替換為擴展后的服務類。

通過這種方式,我們使用?InjectionToken?成功解決了?ServiceA?和?ServiceB?之間的循環(huán)依賴問題。

其他解決循環(huán)依賴的方法

除了使用?InjectionToken,還可以通過以下方法解決循環(huán)依賴問題:

重構代碼:重新設計服務的結構,避免出現循環(huán)依賴。例如,將公共的邏輯提取到一個新的服務中,讓?ServiceA?和?ServiceB?都依賴于這個新服務。

使用 setter 注入:在構造函數中不直接注入依賴項,而是通過 setter 方法在實例創(chuàng)建后再注入依賴項。這樣可以避免在創(chuàng)建實例時就陷入循環(huán)依賴。

import { Injectable } from '@angular/core';

@Injectable({

? providedIn: 'root'

})

export class ServiceA {

? private _serviceB: ServiceB;

? set serviceB(serviceB: ServiceB) {

? ? this._serviceB = serviceB;

? }

}

@Injectable({

? providedIn: 'root'

})

export class ServiceB {

? constructor(private serviceA: ServiceA) {

? ? this.serviceA.serviceB = this;

? }

}

這種方法通過在實例創(chuàng)建后再注入依賴項,避免了構造函數中的循環(huán)依賴問題。但需要注意的是,這種方法可能會使代碼的依賴關系不夠清晰,需要謹慎使用。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容