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