新聞中心
使用輕量級(jí)注入令牌優(yōu)化客戶(hù)應(yīng)用的大小
本頁(yè)面會(huì)提供一個(gè)概念性的概述,它介紹了一種建議庫(kù)開(kāi)發(fā)者使用的依賴(lài)注入技術(shù)。使用輕量級(jí)注入令牌設(shè)計(jì)你的庫(kù),這有助于優(yōu)化那些用到你庫(kù)的客戶(hù)應(yīng)用的發(fā)布包體積。

創(chuàng)新互聯(lián)是工信部頒發(fā)資質(zhì)IDC服務(wù)器商,為用戶(hù)提供優(yōu)質(zhì)的成都移動(dòng)云計(jì)算中心服務(wù)
你可以使用可搖樹(shù)優(yōu)化的提供者來(lái)管理組件和可注入服務(wù)之間的依賴(lài)結(jié)構(gòu),以?xún)?yōu)化發(fā)布包體積。這通常會(huì)確保如果提供的組件或服務(wù)從未被應(yīng)用實(shí)際使用過(guò),那么編譯器就可以從發(fā)布包中刪除它的代碼。
但是,由于 Angular 存儲(chǔ)注入令牌的方式,可能會(huì)導(dǎo)致未用到的組件或服務(wù)最終進(jìn)入發(fā)布包中。本頁(yè)描述了依賴(lài)注入的一種設(shè)計(jì)模式,它通過(guò)使用輕量級(jí)注入令牌來(lái)支持正確的搖樹(shù)優(yōu)化。
這種輕量級(jí)注入令牌設(shè)計(jì)模式對(duì)于庫(kù)開(kāi)發(fā)者來(lái)說(shuō)尤其重要。它可以確保當(dāng)應(yīng)用只用到了你庫(kù)中的某些功能時(shí),可以從客戶(hù)應(yīng)用的發(fā)布包中刪除未使用過(guò)的代碼。
當(dāng)某應(yīng)用用到了你的庫(kù)時(shí),你的庫(kù)中可能會(huì)提供一些客戶(hù)應(yīng)用未用到的服務(wù)。在這種情況下,應(yīng)用開(kāi)發(fā)人員會(huì)期望該服務(wù)是可搖樹(shù)優(yōu)化的,不讓這部分代碼增加應(yīng)用的編譯后大小。由于應(yīng)用開(kāi)發(fā)人員既無(wú)法了解也無(wú)法解決庫(kù)的搖樹(shù)優(yōu)化問(wèn)題,因此這是庫(kù)開(kāi)發(fā)人員的責(zé)任。為了防止未使用的組件被保留下來(lái),你的庫(kù)應(yīng)該使用輕量級(jí)注入令牌這種設(shè)計(jì)模式。
什么時(shí)候令牌會(huì)被保留
為了更好地解釋令牌被保留的條件,我們考慮一個(gè)提供卡片組件的庫(kù),它包含一個(gè)卡片體,還可以包含一個(gè)可選的卡片頭。
…
在一個(gè)可能的實(shí)現(xiàn)中,?? 組件使用 ?@ContentChild()? 或者 ?@ContentChildren()? 來(lái)獲取 ?? 和 ??,如下所示。
@Component({
selector: 'lib-header',
…,
})
class LibHeaderComponent {}
@Component({
selector: 'lib-card',
…,
})
class LibCardComponent {
@ContentChild(LibHeaderComponent)
header: LibHeaderComponent|null = null;
}因?yàn)?nbsp;?? 是可選的,所以元素可以用最小化的形式 ?? 出現(xiàn)在模板中。在這個(gè)例子中,?? 沒(méi)有用過(guò),你可能期望它會(huì)被搖樹(shù)優(yōu)化掉,但事實(shí)并非如此。這是因?yàn)?nbsp;?LibCardComponent ?實(shí)際上包含兩個(gè)對(duì) ?LibHeaderComponent ?引用。
@ContentChild(LibHeaderComponent) header: LibHeaderComponent;- 其中一個(gè)引用位于類(lèi)型位置上 - 即,它把 ?
LibHeaderComponent?用作了類(lèi)型:?header: LibHeaderComponent?;。 - 另一個(gè)引用位于值的位置 - 即,LibHeaderComponent 是 ?
@ContentChild()? 參數(shù)裝飾器的值:?@ContentChild(LibHeaderComponent)?。
編譯器對(duì)這些位置的令牌引用的處理方式也不同。
- 編譯器在從 TypeScript 轉(zhuǎn)換完后會(huì)刪除這些類(lèi)型位置上的引用,所以它們對(duì)于搖樹(shù)優(yōu)化沒(méi)什么影響。
- 編譯器必須在運(yùn)行時(shí)保留值位置上的引用,這就會(huì)阻止該組件被搖樹(shù)優(yōu)化掉。
在這個(gè)例子中,編譯器保留了 ?LibHeaderComponent ?令牌,它出現(xiàn)在了值位置上,這就會(huì)防止所引用的組件被搖樹(shù)優(yōu)化掉,即使應(yīng)用開(kāi)發(fā)者實(shí)際上沒(méi)有在任何地方用過(guò) ??。如果 ?LibHeaderComponent ?很大(代碼、模板和樣式),把它包含進(jìn)來(lái)就會(huì)不必要地大大增加客戶(hù)應(yīng)用的大小。
什么時(shí)候使用輕量級(jí)注入令牌模式
當(dāng)一個(gè)組件被用作注入令牌時(shí),就會(huì)出現(xiàn)搖樹(shù)優(yōu)化的問(wèn)題。有兩種情況可能會(huì)發(fā)生。
- 令牌用在內(nèi)容查詢(xún)中值的位置上。
- 該令牌用作構(gòu)造函數(shù)注入的類(lèi)型說(shuō)明符。
在下面的例子中,兩處對(duì) ?OtherComponent ?令牌的使用導(dǎo)致 ?OtherComponent ?被保留下來(lái)(也就是說(shuō),防止它在未用到時(shí)被搖樹(shù)優(yōu)化掉)。
class MyComponent {
constructor(@Optional() other: OtherComponent) {}
@ContentChild(OtherComponent)
other: OtherComponent|null;
}雖然轉(zhuǎn)換為 JavaScript 時(shí)只會(huì)刪除那些只用作類(lèi)型說(shuō)明符的令牌,但在運(yùn)行時(shí)依賴(lài)注入需要所有這些令牌。這些工作把 ?constructor(@Optional() other: OtherComponent)? 改成了 ?constructor(@Optional() @Inject(OtherComponent) other)?。該令牌現(xiàn)在處于值的位置,并使該搖樹(shù)優(yōu)化器保留該引用。
對(duì)于所有服務(wù),庫(kù)都應(yīng)該使用可搖樹(shù)優(yōu)化的提供者,在根級(jí)而不是組件構(gòu)造函數(shù)中提供依賴(lài)。
使用輕量級(jí)注入令牌
輕量級(jí)注入令牌設(shè)計(jì)模式包括:使用一個(gè)小的抽象類(lèi)作為注入令牌,并在稍后為它提供實(shí)際實(shí)現(xiàn)。該抽象類(lèi)固然會(huì)被留下(不會(huì)被搖樹(shù)優(yōu)化掉),但它很小,對(duì)應(yīng)用程序的大小沒(méi)有任何重大影響。
下例舉例說(shuō)明了這個(gè) ?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;
}在這個(gè)例子中,?LibCardComponent ?的實(shí)現(xiàn)里,?LibHeaderComponent ?既不會(huì)出現(xiàn)在類(lèi)型的位置也不會(huì)出現(xiàn)在值的位置。這樣就可以讓 ?LibHeaderComponent ?完全被搖樹(shù)優(yōu)化掉。?LibHeaderToken ?被留下了,但它只是一個(gè)類(lèi)聲明,沒(méi)有具體的實(shí)現(xiàn)。它很小,并且在編譯后保留時(shí)對(duì)應(yīng)用程序的大小沒(méi)有實(shí)質(zhì)影響。
不過(guò),?LibHeaderComponent ?本身實(shí)現(xiàn)了抽象類(lèi) ?LibHeaderToken?。你可以放心使用這個(gè)令牌作為組件定義中的提供者,讓 Angular 能夠正確地注入具體類(lèi)型。
總結(jié)一下,輕量級(jí)注入令牌模式由以下幾部分組成。
- 一個(gè)輕量級(jí)的注入令牌,它表現(xiàn)為一個(gè)抽象類(lèi)。
- 一個(gè)實(shí)現(xiàn)該抽象類(lèi)的組件定義。
- 注入這種輕量級(jí)模式時(shí)使用 ?
@ContentChild()? 或者 ?@ContentChildren()?。 - 實(shí)現(xiàn)輕量級(jí)注入令牌的提供者,它將輕量級(jí)注入令牌和它的實(shí)現(xiàn)關(guān)聯(lián)起來(lái)。
使用輕量級(jí)注入令牌進(jìn)行 API 定義
那些注入了輕量級(jí)注入令牌的組件可能要調(diào)用注入的類(lèi)中的方法。因?yàn)榱钆片F(xiàn)在是一個(gè)抽象類(lèi),并且可注入組件實(shí)現(xiàn)了那個(gè)抽象類(lèi),所以你還必須在作為輕量級(jí)注入令牌的抽象類(lèi)中聲明一個(gè)抽象方法。該方法的實(shí)現(xiàn)代碼(及其所有相關(guān)代碼)都會(huì)留在可注入組件中,但這個(gè)組件本身仍可被搖樹(shù)優(yōu)化。這樣就能讓父組件以類(lèi)型安全的方式與子組件(如果存在)進(jìn)行通信。
比如,?LibCardComponent ?現(xiàn)在要查詢(xún) ?LibHeaderToken ?而不是 ?LibHeaderComponent?。這個(gè)例子展示了該模式如何讓 ?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();
}
}在這個(gè)例子中,父組件會(huì)查詢(xún)令牌以獲取子組件,并持有結(jié)果組件的引用(如果存在)。在調(diào)用子組件中的方法之前,父組件會(huì)檢查子組件是否存在。如果子組件已經(jīng)被搖樹(shù)優(yōu)化掉,那運(yùn)行期間就沒(méi)有對(duì)它的引用,當(dāng)然也沒(méi)有調(diào)用它的方法。
為你的輕量級(jí)注入令牌命名
輕量級(jí)注入令牌只對(duì)組件有用。Angular 風(fēng)格指南中建議你使用“Component”后綴命名組件。比如“LibHeaderComponent”就遵循這個(gè)約定。
為了維護(hù)組件及其令牌之間的對(duì)應(yīng)關(guān)系,同時(shí)又要區(qū)分它們,推薦的寫(xiě)法是使用組件基本名加上后綴“?Token?”來(lái)命名你的輕量級(jí)注入令牌:“?LibHeaderToken?”。
網(wǎng)頁(yè)標(biāo)題:創(chuàng)新互聯(lián)Angular教程:Angular為庫(kù)準(zhǔn)備的輕量級(jí)注入令牌
本文鏈接:http://m.fisionsoft.com.cn/article/cdscdhp.html


咨詢(xún)
建站咨詢(xún)
