您可能已經(jīng)嘗試過(guò)在 app.component 的 ngOnInit 函數(shù)中執(zhí)行此操作,但意識(shí)到您的數(shù)據(jù)需要更早加載。您可能還嘗試過(guò)實(shí)現(xiàn)解析器,但意識(shí)到它們更適合單個(gè)路由的上下文。以下是在頁(yè)面加載之前加載數(shù)據(jù)的另一種方法,您可能還不知道:APP_INITIALIZER。
定義
在深入研究代碼之前,讓我們更好地了解APP_INITIALIZER是什么以及它是如何工作的。
APP_INITIALIZER令牌允許您為應(yīng)用程序提供其他初始化函數(shù)。初始化函數(shù)(您可能已經(jīng)從名稱(chēng)中收集到)在應(yīng)用初始化期間執(zhí)行。這些函數(shù)的返回類(lèi)型必須是 void、Promise 或可觀察的。如果從這些函數(shù)中的任何一個(gè)返回 Promise 或可觀察量,則應(yīng)用程序僅在它們完成后才初始化。
簡(jiǎn)單來(lái)說(shuō),我喜歡把它看作是定義一個(gè)“啟動(dòng)”階段,在這個(gè)階段中,你可以確保你的應(yīng)用正常運(yùn)行所需的所有核心數(shù)據(jù)在用戶(hù)開(kāi)始與之交互之前都已加載。
以下是可以在初始化函數(shù)中加載的內(nèi)容的幾個(gè)示例:
翻譯
經(jīng)過(guò)身份驗(yàn)證的用戶(hù)數(shù)據(jù)
配置數(shù)據(jù)
例
為簡(jiǎn)單起見(jiàn),讓我們以加載當(dāng)前經(jīng)過(guò)身份驗(yàn)證的用戶(hù)的數(shù)據(jù)為例。
大多數(shù) Web 應(yīng)用在屏幕右上角顯示當(dāng)前用戶(hù)的個(gè)人資料圖片和名稱(chēng),因此讓我們實(shí)現(xiàn)類(lèi)似的內(nèi)容。我將使用一個(gè)新的角度安裝(14.1)和引導(dǎo)5作為CSS:
現(xiàn)在打開(kāi)您的并導(dǎo)入引導(dǎo):styles.scss
如果您使用的是不同版本的Angular,則某些導(dǎo)入和語(yǔ)法可能會(huì)有所不同,因此,如果您要遵循代碼,請(qǐng)注意這一點(diǎn)。
奠定基礎(chǔ)
讓我們從創(chuàng)建一個(gè)負(fù)責(zé)提供當(dāng)前用戶(hù)數(shù)據(jù)的服務(wù)開(kāi)始,該服務(wù)現(xiàn)在將如下所示:
這將是我們數(shù)據(jù)的默認(rèn)值,直到我們發(fā)出請(qǐng)求以獲取實(shí)際的當(dāng)前用戶(hù)數(shù)據(jù)。
讓我們利用這些數(shù)據(jù)并將其顯示在屏幕的右上角。為了簡(jiǎn)單起見(jiàn),我們將直接在應(yīng)用程序組件中執(zhí)行此操作。
首先,我們注入我們的用戶(hù)服務(wù):
然后對(duì)于網(wǎng)頁(yè):
我強(qiáng)調(diào)了我們實(shí)際顯示用戶(hù)的姓名和個(gè)人資料圖片的重要部分。
現(xiàn)在我們已經(jīng)奠定了基礎(chǔ),剩下要做的就是實(shí)現(xiàn)一個(gè)函數(shù)來(lái)獲取實(shí)際的用戶(hù)數(shù)據(jù),然后查看我們將在何時(shí)何地調(diào)用它。
我不打算為此使用實(shí)際的后端服務(wù),而是在我們的資產(chǎn)文件夾中創(chuàng)建一個(gè)JSON文件,我們將在其中對(duì)數(shù)據(jù)進(jìn)行硬編碼:
我們將定義負(fù)責(zé)獲取 內(nèi)部數(shù)據(jù)的函數(shù),如下所示:UserService
不要忘記導(dǎo)入 中的 .HttpClientModuleAppModule
實(shí)現(xiàn)APP_INITIALIZER
正如我們?cè)诙x部分中了解到的那樣,APP_INITIALIZER讓我們定義其他初始化函數(shù),因此現(xiàn)在讓我們?cè)趩为?dú)的文件中定義一個(gè)。
您可以根據(jù)需要命名文件和函數(shù)。我主要堅(jiān)持使用更通用的名稱(chēng),因?yàn)槲彝ǔJ褂?如果您更喜歡以不同的方式執(zhí)行,則可以命名此函數(shù)或類(lèi)似名稱(chēng)(因?yàn)檫@是它唯一執(zhí)行的操作),然后創(chuàng)建單獨(dú)的函數(shù)來(lái)加載您可能需要的任何其他數(shù)據(jù)。forkJoinloadUserDataFactory
現(xiàn)在,唯一要做的就是將此函數(shù)標(biāo)記為APP_INITIALIZER以便 Angular 知道在應(yīng)用初始化期間執(zhí)行它。為此,我們需要將以下提供程序添加到 AppModule 中的提供程序數(shù)組中:
就是這樣。如果現(xiàn)在刷新頁(yè)面,您應(yīng)該會(huì)看到一個(gè)大約 1 秒的空白頁(yè)(由于我們?cè)讷@取 JSON 文件時(shí)添加的延遲),之后頁(yè)面將加載,并在右上角顯示實(shí)際的用戶(hù)名和頭像(在 user.json 文件中指定的用戶(hù)名和頭像)。
需要考慮的事項(xiàng)
可能最重要的一點(diǎn)是,如果從任何初始值設(shè)定項(xiàng)函數(shù)錯(cuò)誤返回的可觀察值,則應(yīng)用將不再初始化。在我們的示例中,您可以通過(guò)重命名或臨時(shí)刪除文件來(lái)查看此操作,這將導(dǎo)致 Observable 失敗并顯示 404 錯(cuò)誤。因此,您將被困在最初的空白頁(yè)上。
若要阻止這種情況發(fā)生,請(qǐng)始終確保使用運(yùn)算符捕獲任何潛在錯(cuò)誤,并為數(shù)據(jù)提供默認(rèn)值或?qū)⒂脩?hù)重定向到特定的錯(cuò)誤頁(yè)面,您可以在其中向他們提供出錯(cuò)的詳細(xì)信息以及如何繼續(xù)前進(jìn)。在我們的示例中,重定向到錯(cuò)誤頁(yè)面可能如下所示 - 如果您想嘗試此操作,請(qǐng)不要忘記通過(guò)更新 AppModule 中提供程序的鍵來(lái)將 添加為依賴(lài)項(xiàng),然后創(chuàng)建新頁(yè)面及其路由:user.json catchError Router deps
您看到 1 秒鐘的空白頁(yè)實(shí)際上是 .發(fā)生這種情況的原因是,由于在可觀察完成之前未初始化應(yīng)用,因此不會(huì)填充該元素,因此您看不到任何內(nèi)容。我通常做的是添加一個(gè)加載的圖像/文本作為元素的子級(jí)。當(dāng)應(yīng)用完成初始化時(shí),你放入 其中的任何內(nèi)容都將被覆蓋。我給你一個(gè)例子,你可以在下面嘗試。如果要使用它,請(qǐng)考慮在初始化AppFactory函數(shù)中增加可觀察量的延遲。index.html<app-root><app-root><app-root>
習(xí)慣使用 RxJS(除非你使用的是承諾),因?yàn)橥ǔG闆r下,你需要使用一堆 RxJS 函數(shù)和運(yùn)算符才能獲得正確的結(jié)果,是我經(jīng)常在這樣的情況下使用的。例如,在我們的示例中,我們只處理了用戶(hù)登錄時(shí)的情況,但如果用戶(hù)實(shí)際上是訪客,該怎么辦?在這種情況下,我們可能希望堅(jiān)持使用我們定義的默認(rèn)數(shù)據(jù)。在單個(gè)流中執(zhí)行此操作的一種方法看起來(lái)像這樣 - 請(qǐng)記住,這只是一個(gè)示例,由于我們尚未一起定義任何內(nèi)容,因此在當(dāng)前項(xiàng)目中不會(huì)開(kāi)箱即用 :forkJoin iif switchMap map catchError tap authService