摘要:告訴注入器如何創(chuàng)建該服務(wù),可以通過(guò)設(shè)置元數(shù)據(jù)來(lái)配置注入器種方式在服務(wù)本身的裝飾器中。裝飾器具有一個(gè)名叫的元數(shù)據(jù)選項(xiàng),在這里指定把被裝飾類的放到注入器中,或某個(gè)特定的注入器中。
angular 服務(wù)隨記 依賴注入
創(chuàng)建服務(wù)需要用到Injectable,@Injectable() 裝飾器把類標(biāo)記為可供注入的服務(wù),不過(guò)在使用該服務(wù)的 provider 配置好 Angular 的依賴注入器之前,Angular 實(shí)際上無(wú)法將其注入到任何位置。
provider告訴注入器如何創(chuàng)建該服務(wù),可以通過(guò)設(shè)置元數(shù)據(jù)來(lái)配置注入器(3種方式):
在服務(wù)本身的 @Injectable() 裝飾器中。
在 NgModule 的 @NgModule() 裝飾器中。
在組件的 @Component() 裝飾器中。
@Injectable() 裝飾器具有一個(gè)名叫 providedIn 的元數(shù)據(jù)選項(xiàng),在這里指定把被裝飾類的provider放到 root 注入器中,或某個(gè)特定 NgModule 的注入器中。
@NgModule() 和 @Component() 裝飾器都有用一個(gè) providers 元數(shù)據(jù)選項(xiàng),在那里你可以配置 NgModule 級(jí)或組件級(jí)的注入器。
注入器與服務(wù)實(shí)例在某個(gè)注入器范圍內(nèi),服務(wù)是單例的。應(yīng)用只有一個(gè)根注入器,angular具有多級(jí)注入器系統(tǒng),以為者下級(jí)注入器可以創(chuàng)建自己的服務(wù)實(shí)例。
每當(dāng) Angular 創(chuàng)建一個(gè)在 @Component() 中指定了 providers 的組件實(shí)例時(shí),它也會(huì)為該實(shí)例創(chuàng)建一個(gè)新的子注入器。 類似的,當(dāng)在運(yùn)行期間加載一個(gè)新的 NgModule 時(shí)(即lazy module),Angular 也可以為它創(chuàng)建一個(gè)擁有自己的提供商的注入器。
借助注入器繼承機(jī)制,仍然可以把全應(yīng)用級(jí)的服務(wù)注入到這些組件中。 組件的注入器是其父組件注入器的子節(jié)點(diǎn),也是其父節(jié)點(diǎn)的父節(jié)點(diǎn)的后代,以此類推,直到應(yīng)用的根注入器為止。 Angular 可以注入該繼承譜系中任何一個(gè)注入器提供的服務(wù)。
模塊化編程時(shí),service、component、pipe等最好都放在module中,需要引入這些服務(wù)時(shí),通過(guò)導(dǎo)入module來(lái)引用,不要直接import service 和component,這不符合模塊化思想。多級(jí)注入系統(tǒng)
應(yīng)用程序中有一個(gè)與組件樹(shù)平行的注入器樹(shù),對(duì)于在什么級(jí)別上注入會(huì)最終導(dǎo)致:
最終包的大小
服務(wù)的范圍
服務(wù)的生命周期
當(dāng)在服務(wù)自身的@Injectable()裝飾器中指定provider時(shí),CLI生產(chǎn)模式所用的優(yōu)化工具可以進(jìn)行搖樹(shù)優(yōu)化,它會(huì)移除那些沒(méi)有用過(guò)的服務(wù),搖樹(shù)優(yōu)化生成的包更小。
三級(jí)providerroot級(jí),是AppModule全局的,配置方法已提。
NgModule級(jí),兩種方法:可以在module的@NgModule 的 provider 元數(shù)據(jù)中指定;也可以在@injectable() 的providerIn選項(xiàng)中指定某個(gè)模塊類
如果模塊是lazy modole,需要使用@NgModule的provider選項(xiàng)。
組件級(jí)為每個(gè)component實(shí)例配置自己的注入器
無(wú)論對(duì)于根級(jí)注入器還是模塊級(jí)注入器,服務(wù)實(shí)例的生存期都和應(yīng)用或模塊本身相同。Angular 可以把這個(gè)服務(wù)實(shí)例注入到任何需要它的類中(即app內(nèi)是單例的)。Angular 只能把相應(yīng)的服務(wù)注入到該組件實(shí)例或其下級(jí)組件實(shí)例中,而不能把這個(gè)服務(wù)實(shí)例注入到其它地方(即組件內(nèi)并不是單例的)。注入器冒泡
當(dāng)一個(gè)組件申請(qǐng)獲得一個(gè)依賴時(shí),Angular 先嘗試用該組件自己的注入器來(lái)滿足它。 如果該組件的注入器沒(méi)有找到對(duì)應(yīng)的提供商,它就把這個(gè)申請(qǐng)轉(zhuǎn)給它父組件的注入器來(lái)處理。 如果那個(gè)注入器也無(wú)法滿足這個(gè)申請(qǐng),它就繼續(xù)轉(zhuǎn)給它在注入器樹(shù)中的父注入器。 這個(gè)申請(qǐng)繼續(xù)往上冒泡 —— 直到 Angular 找到一個(gè)能處理此申請(qǐng)的注入器或者超出了組件樹(shù)中的祖先位置為止。 如果超出了組件樹(shù)中的祖先還未找到,Angular 就會(huì)拋出一個(gè)錯(cuò)誤。
單例服務(wù)在angular中創(chuàng)建單例服務(wù)有兩種方式:
在創(chuàng)建服務(wù)時(shí)聲明該服務(wù)在應(yīng)用的根上提供
把該服務(wù)包含在AppModule或者某個(gè)只會(huì)被AppModule導(dǎo)入的模塊中
這里第一條很容易理解。重點(diǎn)第二條:當(dāng)通過(guò)@NgMododule()來(lái)聲明一個(gè)serivce時(shí),這個(gè)服務(wù)在AppModule內(nèi)將會(huì)是單例的,當(dāng)一個(gè)module中提供了一個(gè)service,當(dāng)另一個(gè)lazy module導(dǎo)入了這個(gè)模塊時(shí),angular會(huì)為它創(chuàng)一個(gè)子注入器,會(huì)重新創(chuàng)建service的實(shí)例,此service也就多了一個(gè)實(shí)例。forRoot()
如果某個(gè)模塊同時(shí)提供了服務(wù)提供商和可聲明對(duì)象(組件、指令、管道),那么當(dāng)在某個(gè)子注入器中加載它的時(shí)候(比如lazy module),就會(huì)生成多個(gè)該服務(wù)提供商的實(shí)例。 而存在多個(gè)實(shí)例會(huì)導(dǎo)致一些問(wèn)題,因?yàn)檫@些實(shí)例會(huì)屏蔽掉根注入器中該服務(wù)提供商的實(shí)例,而它的本意可能是作為單例對(duì)象使用的。 因此,Angular 提供了一種方式來(lái)把服務(wù)提供商從該模塊中分離出來(lái),以便該模塊既可以帶著 providers 被根模塊導(dǎo)入,也可以不帶 providers 被子模塊導(dǎo)入。
如上文所述,當(dāng)在運(yùn)行期間加載一個(gè)新的 NgModule 時(shí)(即lazy module),Angular 也可以為它創(chuàng)建一個(gè)注入器,所以此時(shí)導(dǎo)入的其他模塊中的service就生成了多個(gè)實(shí)例,而forRoot可以保證并不創(chuàng)建新的service實(shí)例,而是去引用root注入器中的service實(shí)例,也就保證了service依然是個(gè)單例服務(wù)。
Code在懶加載模塊中導(dǎo)入有service的TestDIModule模塊
@NgModule({ imports: [ CommonModule, BatteryRoutingModule, TestDIModule ], declarations: [BatteryWidgetComponent, BatteryTwoComponent, DemoComponent] })
在TestDIModule模塊中
@NgModule({ imports: [ CommonModule ], declarations: [TestDiComponent], exports: [TestDiComponent], providers: [ ] }) export class TestDIModule { static forRoot(): ModuleWithProviders { return { ngModule: TestDIModule, providers: [ TestDiService ] }; } }
在根模塊中引入TestDIModule模塊
imports: [ BrowserModule, TestDIModule.forRoot(), ],
最后在根模塊路由中添加這個(gè)懶加載模塊
const routes: Routes = [ { path: "battery", loadChildren: "./battery-widget/battery.widget.module#BatteryWidgetModule" }, ]; @NgModule({ exports: [ RouterModule ], imports: [ RouterModule.forRoot(routes) ], })
作為測(cè)試,可以在TestDIModule中的service中打log看一下
import { Injectable, ModuleWithProviders } from "@angular/core"; import { TestDIModule } from "./test-di.module" @Injectable() export class TestDiService { constructor() { console.log("->TestDiService"); } addCoount() { this.count++; console.log("->count", this.count); } count = 0; }
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/104103.html
摘要:無(wú)主題,內(nèi)容為感觸較深的一些答疑探討等,摘自多篇文章,侵刪為什么是單線程的單線程,與它的用途有關(guān)。作為瀏覽器腳本語(yǔ)言,的主要用途是與用戶互動(dòng),以及操作。這決定了它只能是單線程,否則會(huì)帶來(lái)很復(fù)雜的同步問(wèn)題。摘自運(yùn)行機(jī)制詳解再談作者阮一峰 無(wú)主題,內(nèi)容為感觸較深的一些答疑、探討等,摘自多篇文章,侵刪 1、為什么JavaScript是單線程 JavaScript的單線程,與它的用途有關(guān)。作...
摘要:此過(guò)程中,頁(yè)面的解析與用戶的交互都是阻塞的。非阻塞腳本延時(shí)腳本可以給標(biāo)簽添加一個(gè)屬性,這個(gè)屬性表明元素中的腳本不打算修改,因此代碼可以稍后執(zhí)行。此技術(shù)的重點(diǎn)在于無(wú)論在何處啟動(dòng)下載,腳本的下載和運(yùn)行都不會(huì)阻塞頁(yè)面的處理過(guò)程。 當(dāng)瀏覽器遇到標(biāo)簽時(shí),頁(yè)面的加載、介些都會(huì)停下來(lái),運(yùn)行此javascript代碼,然后再繼續(xù)加載。這種事情同樣會(huì)發(fā)生在那些以src屬性調(diào)用的外部腳本,瀏覽器首先下載外...
摘要:操作的代價(jià)非常昂貴,對(duì)元素節(jié)點(diǎn)的訪問(wèn)和修改樣式布局的改變以及事件的綁定都影響著網(wǎng)頁(yè)的性能。所以,盡量減少對(duì)布局信息的查詢次數(shù),并用局部變量參與計(jì)算。當(dāng)動(dòng)畫(huà)結(jié)束時(shí),重新定位,從而只一次下移文檔其他元素的位置。這樣可以最小化事件句柄數(shù)量。 DOM操作的代價(jià)非常昂貴,對(duì)元素節(jié)點(diǎn)的訪問(wèn)和修改、樣式、布局的改變以及DOM事件的綁定都影響著網(wǎng)頁(yè)的性能。 批量修改DOM 如果要對(duì)元素節(jié)...
閱讀 3020·2021-10-12 10:12
閱讀 3073·2021-09-22 16:04
閱讀 3306·2019-08-30 15:54
閱讀 2616·2019-08-29 16:59
閱讀 2929·2019-08-29 16:08
閱讀 880·2019-08-29 11:20
閱讀 3503·2019-08-28 18:08
閱讀 661·2019-08-26 13:43