W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗(yàn)值獎勵
本頁面會提供一個概念性的概述,它介紹了一種建議庫開發(fā)者使用的依賴注入技術(shù)。使用輕量級注入令牌設(shè)計(jì)你的庫,這有助于優(yōu)化那些用到你庫的客戶應(yīng)用的發(fā)布包體積。
你可以使用可搖樹優(yōu)化的提供者來管理組件和可注入服務(wù)之間的依賴結(jié)構(gòu),以優(yōu)化發(fā)布包體積。這通常會確保如果提供的組件或服務(wù)從未被應(yīng)用實(shí)際使用過,那么編譯器就可以從發(fā)布包中刪除它的代碼。
但是,由于 Angular 存儲注入令牌的方式,可能會導(dǎo)致未用到的組件或服務(wù)最終進(jìn)入發(fā)布包中。本頁描述了依賴注入的一種設(shè)計(jì)模式,它通過使用輕量級注入令牌來支持正確的搖樹優(yōu)化。
這種輕量級注入令牌設(shè)計(jì)模式對于庫開發(fā)者來說尤其重要。它可以確保當(dāng)應(yīng)用只用到了你庫中的某些功能時,可以從客戶應(yīng)用的發(fā)布包中刪除未使用過的代碼。
當(dāng)某應(yīng)用用到了你的庫時,你的庫中可能會提供一些客戶應(yīng)用未用到的服務(wù)。在這種情況下,應(yīng)用開發(fā)人員會期望該服務(wù)是可搖樹優(yōu)化的,不讓這部分代碼增加應(yīng)用的編譯后大小。由于應(yīng)用開發(fā)人員既無法了解也無法解決庫的搖樹優(yōu)化問題,因此這是庫開發(fā)人員的責(zé)任。為了防止未使用的組件被保留下來,你的庫應(yīng)該使用輕量級注入令牌這種設(shè)計(jì)模式。
為了更好地解釋令牌被保留的條件,我們考慮一個提供卡片組件的庫,它包含一個卡片體,還可以包含一個可選的卡片頭。
<lib-card>
<lib-header>…</lib-header>
</lib-card>
在一個可能的實(shí)現(xiàn)中,?<lib-card>
? 組件使用 ?@ContentChild()
? 或者 ?@ContentChildren()
? 來獲取 ?<lib-header>
? 和 ?<lib-body>
?,如下所示。
@Component({
selector: 'lib-header',
…,
})
class LibHeaderComponent {}
@Component({
selector: 'lib-card',
…,
})
class LibCardComponent {
@ContentChild(LibHeaderComponent)
header: LibHeaderComponent|null = null;
}
因?yàn)?nbsp;?<lib-header>
? 是可選的,所以元素可以用最小化的形式 ?<lib-card></lib-card>
? 出現(xiàn)在模板中。在這個例子中,?<lib-header>
? 沒有用過,你可能期望它會被搖樹優(yōu)化掉,但事實(shí)并非如此。這是因?yàn)?nbsp;?LibCardComponent
?實(shí)際上包含兩個對 ?LibHeaderComponent
?引用。
@ContentChild(LibHeaderComponent) header: LibHeaderComponent;
LibHeaderComponent
?用作了類型:?header: LibHeaderComponent
?;。
@ContentChild()
? 參數(shù)裝飾器的值:?@ContentChild(LibHeaderComponent)
?。編譯器對這些位置的令牌引用的處理方式也不同。
在這個例子中,編譯器保留了 ?LibHeaderComponent
?令牌,它出現(xiàn)在了值位置上,這就會防止所引用的組件被搖樹優(yōu)化掉,即使應(yīng)用開發(fā)者實(shí)際上沒有在任何地方用過 ?<lib-header>
?。如果 ?LibHeaderComponent
?很大(代碼、模板和樣式),把它包含進(jìn)來就會不必要地大大增加客戶應(yīng)用的大小。
當(dāng)一個組件被用作注入令牌時,就會出現(xiàn)搖樹優(yōu)化的問題。有兩種情況可能會發(fā)生。
在下面的例子中,兩處對 ?OtherComponent
?令牌的使用導(dǎo)致 ?OtherComponent
?被保留下來(也就是說,防止它在未用到時被搖樹優(yōu)化掉)。
class MyComponent {
constructor(@Optional() other: OtherComponent) {}
@ContentChild(OtherComponent)
other: OtherComponent|null;
}
雖然轉(zhuǎn)換為 JavaScript 時只會刪除那些只用作類型說明符的令牌,但在運(yùn)行時依賴注入需要所有這些令牌。這些工作把 ?constructor(@Optional() other: OtherComponent)
? 改成了 ?constructor(@Optional() @Inject(OtherComponent) other)
?。該令牌現(xiàn)在處于值的位置,并使該搖樹優(yōu)化器保留該引用。
對于所有服務(wù),庫都應(yīng)該使用可搖樹優(yōu)化的提供者,在根級而不是組件構(gòu)造函數(shù)中提供依賴。
輕量級注入令牌設(shè)計(jì)模式包括:使用一個小的抽象類作為注入令牌,并在稍后為它提供實(shí)際實(shí)現(xiàn)。該抽象類固然會被留下(不會被搖樹優(yōu)化掉),但它很小,對應(yīng)用程序的大小沒有任何重大影響。
下例舉例說明了這個 ?LibHeaderComponent
?的工作原理。
abstract class LibHeaderToken {}
@Component({
selector: 'lib-header',
providers: [
{provide: LibHeaderToken, useExisting: LibHeaderComponent}
]
…,
})
class LibHeaderComponent extends LibHeaderToken {}
@Component({
selector: 'lib-card',
…,
})
class LibCardComponent {
@ContentChild(LibHeaderToken) header: LibHeaderToken|null = null;
}
在這個例子中,?LibCardComponent
?的實(shí)現(xiàn)里,?LibHeaderComponent
?既不會出現(xiàn)在類型的位置也不會出現(xiàn)在值的位置。這樣就可以讓 ?LibHeaderComponent
?完全被搖樹優(yōu)化掉。?LibHeaderToken
?被留下了,但它只是一個類聲明,沒有具體的實(shí)現(xiàn)。它很小,并且在編譯后保留時對應(yīng)用程序的大小沒有實(shí)質(zhì)影響。
不過,?LibHeaderComponent
?本身實(shí)現(xiàn)了抽象類 ?LibHeaderToken
?。你可以放心使用這個令牌作為組件定義中的提供者,讓 Angular 能夠正確地注入具體類型。
總結(jié)一下,輕量級注入令牌模式由以下幾部分組成。
@ContentChild()
? 或者 ?@ContentChildren()
?。
那些注入了輕量級注入令牌的組件可能要調(diào)用注入的類中的方法。因?yàn)榱钆片F(xiàn)在是一個抽象類,并且可注入組件實(shí)現(xiàn)了那個抽象類,所以你還必須在作為輕量級注入令牌的抽象類中聲明一個抽象方法。該方法的實(shí)現(xiàn)代碼(及其所有相關(guān)代碼)都會留在可注入組件中,但這個組件本身仍可被搖樹優(yōu)化。這樣就能讓父組件以類型安全的方式與子組件(如果存在)進(jìn)行通信。
比如,?LibCardComponent
?現(xiàn)在要查詢 ?LibHeaderToken
?而不是 ?LibHeaderComponent
?。這個例子展示了該模式如何讓 ?LibCardComponent
?與 ?LibHeaderComponent
?通信,卻不用實(shí)際引用 ?LibHeaderComponent
?。
abstract class LibHeaderToken {
abstract doSomething(): void;
}
@Component({
selector: 'lib-header',
providers: [
{provide: LibHeaderToken, useExisting: LibHeaderComponent}
]
…,
})
class LibHeaderComponent extends LibHeaderToken {
doSomething(): void {
// Concrete implementation of `doSomething`
}
}
@Component({
selector: 'lib-card',
…,
})
class LibCardComponent implement AfterContentInit {
@ContentChild(LibHeaderToken)
header: LibHeaderToken|null = null;
ngAfterContentInit(): void {
this.header && this.header.doSomething();
}
}
在這個例子中,父組件會查詢令牌以獲取子組件,并持有結(jié)果組件的引用(如果存在)。在調(diào)用子組件中的方法之前,父組件會檢查子組件是否存在。如果子組件已經(jīng)被搖樹優(yōu)化掉,那運(yùn)行期間就沒有對它的引用,當(dāng)然也沒有調(diào)用它的方法。
輕量級注入令牌只對組件有用。Angular 風(fēng)格指南中建議你使用“Component”后綴命名組件。比如“LibHeaderComponent”就遵循這個約定。
為了維護(hù)組件及其令牌之間的對應(yīng)關(guān)系,同時又要區(qū)分它們,推薦的寫法是使用組件基本名加上后綴“?Token
?”來命名你的輕量級注入令牌:“?LibHeaderToken
?”。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: