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

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

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

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

以下是一個(gè)簡(jiǎ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?的構(gòu)造函數(shù)依賴于?ServiceB,而?ServiceB?的構(gòu)造函數(shù)又依賴于?ServiceA,這就形成了循環(huán)依賴。當(dāng) Angular 嘗試創(chuàng)建?ServiceA?的實(shí)例時(shí),需要先創(chuàng)建?ServiceB?的實(shí)例,而創(chuàng)建?ServiceB?的實(shí)例又需要先創(chuàng)建?ServiceA?的實(shí)例,從而陷入無(wú)限循環(huán)。

2.?InjectionToken?介紹

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

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

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

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

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

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

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

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

// 創(chuàng)建一個(gè) InjectionToken 用于標(biāo)識(shí)原始的 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?數(shù)組中進(jìn)行配置:

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 } // 這里可以根據(jù)需要替換為擴(kuò)展后的 ServiceB

? ],

? bootstrap: [AppComponent]

})

export class AppModule {}

代碼解釋

創(chuàng)建?InjectionToken:ORIGINAL_SERVICE_B?是一個(gè)?InjectionToken,用于標(biāo)識(shí)原始的?ServiceB。

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

模塊配置:在?AppModule?的?providers?數(shù)組中,將?ORIGINAL_SERVICE_B?與?ServiceB?類關(guān)聯(lián)起來(lái),當(dāng)請(qǐng)求?ORIGINAL_SERVICE_B?時(shí),Angular 會(huì)創(chuàng)建一個(gè)?ServiceB?的實(shí)例。同時(shí),也可以根據(jù)需要將?ServiceB?替換為擴(kuò)展后的服務(wù)類。

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

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

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

重構(gòu)代碼:重新設(shè)計(jì)服務(wù)的結(jié)構(gòu),避免出現(xiàn)循環(huán)依賴。例如,將公共的邏輯提取到一個(gè)新的服務(wù)中,讓?ServiceA?和?ServiceB?都依賴于這個(gè)新服務(wù)。

使用 setter 注入:在構(gòu)造函數(shù)中不直接注入依賴項(xiàng),而是通過(guò) setter 方法在實(shí)例創(chuàng)建后再注入依賴項(xiàng)。這樣可以避免在創(chuàng)建實(shí)例時(shí)就陷入循環(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;

? }

}

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

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

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容