Angular 更關(guān)注性能的升級方式

2022-07-22 15:32 更新

更關(guān)注性能的升級方式

Angular 是當(dāng)前以及未來的 Angular 名稱。
AngularJS 特指 Angular 的所有 1.x 版本。

本指南介紹了一些用來將 AngularJS 項目高效地逐塊遷移到 Angular 平臺上的工具。 本章和從 AngularJS 升級很像,但是這里會用輔助函數(shù) ?downgradeModule()? 取代 ?UpgradeModule?。這會影響到應(yīng)用如何啟動,以及變更檢測事件如何在兩個框架之間傳播。 它能讓你逐步升級,并提高混合式應(yīng)用的運行速度,并讓你能在升級過程中盡早用上 Angular 中的最新特性。

準備工作

在討論你應(yīng)該如何用 ?downgradeModule()? 來創(chuàng)建混合式應(yīng)用之前,你可以先采取一些措施來簡化升級過程,甚至在開始升級之前就可以做。 無論你用哪種方式升級,這些步驟都是一樣的,請參考從 AngularJS 升級的準備工作部分。

使用 ngUpgrade 升級

使用 Angular 中的 ?ngUpgrade ?庫,你可以通過構(gòu)建混合式應(yīng)用來逐步升級現(xiàn)有的 AngularJS 應(yīng)用。在這些混合式應(yīng)用中,你可以混用 AngularJS 和 Angular 的組件與服務(wù),并讓它們天衣無縫地進行互操作。 這意味著你不用一次性完成遷移工作,因為在過渡階段兩個框架可以自然共存。

ngUpgrade 的工作原理

無論選擇 ?downgradeModule()? 還是 ?UpgradeModule?,升級的基本原則都是一樣的:無論是混合式應(yīng)用背后的心智模型,還是 ?upgrade/static? 的用法。 要了解更多,參閱從 AngularJS 升級的 ngUpgrade 工作原理部分。

從 AngularJS 升級中的變更檢測部分僅僅適用于使用 ?UpgradeModule ?的應(yīng)用。 雖然你處理變更檢測的方式和 ?downgradeModule()?(本章的重點)不同,不過讀一下變更檢測部分還是能為后續(xù)內(nèi)容提供一些有用的上下文知識。

使用 downgradeModule() 進行變更檢測

如前所述,?downgradeModule()? 和 ?UpgradeModule ?之間的一個關(guān)鍵區(qū)別,就是如何進行變更檢測,以及檢測結(jié)果如何在兩個框架之間傳播。

使用 ?UpgradeModule?,兩套變更檢測系統(tǒng)綁得更緊密一些。 一旦應(yīng)用中的 AngularJS 部分發(fā)生了某些變化,變更檢測就會自動在 Angular 部分觸發(fā)它,反之亦然。 這很方便,因為它保證了任何一個框架都不會丟失重要的變更。不過,其實大多數(shù)情況下并不需要運行這些額外的變更檢測。

而 ?downgradeModule()? 會避免顯式觸發(fā)變更檢測,除非它確信應(yīng)用的其它部分對此感興趣。 比如,如果被降級的組件定義了 ?@Input()?,當(dāng)那個值發(fā)生變化時,應(yīng)用就可能需要知道。 因此,?downgradeComponent()? 就會自動在該組件上觸發(fā)變更檢測。

但是,大多數(shù)情況下,應(yīng)用的其它地方并不會關(guān)心某個組件中進行的局部更改。 比如,如果用戶點擊了某個表單的提交按鈕,通常會由組件自行處理這個操作的結(jié)果。 話雖如此,但在某些情況下,你可能希望把這些變化傳播到應(yīng)用中由另一個框架控制的部分。 這時候,你就有責(zé)任通過手動觸發(fā)變更檢測來通知相關(guān)方。

如果你希望某些代碼片段在應(yīng)用的 AngularJS 部分觸發(fā)變更檢測,就要把它包在 scope.$apply() 中。 同樣,要想在 Angular 中觸發(fā)變更檢測,就要調(diào)用 ?ngZone.run()?。

很多情況下,是否運行額外的變更檢測可能并不重要。不過,在較大或變更檢測較多的應(yīng)用中,它們可能會產(chǎn)生顯著地影響。 通過讓你更精細的控制變更檢測的傳播方式,?downgradeModule()? 可以讓你的混合式應(yīng)用達到更好地性能。

使用 downgradeModule()

AngularJS 和 Angular 都有自己的模塊概念,來幫你把應(yīng)用按功能組織成內(nèi)聚的代碼塊。

它們在架構(gòu)和實現(xiàn)方面的細節(jié)有很大不同。在 AngularJS 中,你可以用 angular.module() 指定名字和依賴,以創(chuàng)建一個模塊。 然后,你可以使用它的各種方法添加資產(chǎn)。在 Angular 中,你要創(chuàng)建一個帶有 ?NgModule ?裝飾器的類,靠這個裝飾器的元數(shù)據(jù)來描述這些資產(chǎn)。

在混合式應(yīng)用中,你同時運行著兩個框架。這意味著你至少需要一個來自 AngularJS 的模塊和一個來自 Angular 的模塊。

大多數(shù)情況下,你可以使用與常規(guī)應(yīng)用程序相同的方式來指定模塊。然后,使用 ?upgrade/static? 輔助函數(shù)來讓兩個框架了解對方使用的資產(chǎn)。這叫做"升級(upgrading)"和"降級(downgrading)"。

定義
  • 升級:讓 AngularJS 中的資產(chǎn),比如組件或服務(wù),可用于應(yīng)用中的 Angular 部分。
  • 降級:讓 Angular 中的資產(chǎn),比如組件或服務(wù),可用于應(yīng)用中的 AngularJS 部分

依賴互聯(lián)中最重要的部分之一是把兩個主模塊聯(lián)結(jié)在一起。這就是 ?downgradeModule()? 的用武之地。使用它來創(chuàng)建 AngularJS 模塊(你可以在 AngularJS 主模塊中把這個模塊用作依賴項),該模塊將引導(dǎo)你的 Angular 主模塊,并啟動混合式應(yīng)用中的 Angular 部分。從某種意義上說,它把 NgModule "降級"成了 AngularJS 模塊。

有幾點需要注意:

  1. 你不必把 Angular 模塊直接傳給 ?downgradeModule()?。?downgradeModule()? 所需要的只是一個用來創(chuàng)建模塊實例 "配方"(比如工廠函數(shù))。
  2. 除非應(yīng)用實際用到了,否則不會初始化這個 Angular 模塊。

下面是如何使用 ?downgradeModule()? 來聯(lián)結(jié)兩個模塊的例子。

// Import `downgradeModule()`.
import { downgradeModule } from '@angular/upgrade/static';

// Use it to downgrade the Angular module to an AngularJS module.
const downgradedModule = downgradeModule(MainAngularModuleFactory);

// Use the downgraded module as a dependency to the main AngularJS module.
angular.module('mainAngularJsModule', [
  downgradedModule
]);

為 Angular 模塊指定一個工廠

如前所述,?downgradeModule()? 需要知道如何實例化 Angular 模塊。你可以通過提供可以創(chuàng)建 Angular 模塊實例的工廠函數(shù)來定義該配方。 ?downgradeModule()? 接受兩種類型的工廠函數(shù):

  1. ?NgModuleFactory ?
  2. ?(extraProviders: StaticProvider[]) => Promise<NgModuleRef>?

當(dāng)傳入 ?NgModuleFactory ?時,?downgradeModule()? 會把它傳給 ?platformBrowser ?的 ?bootstrapModuleFactory()? 來實例化模塊。它與預(yù)先(AOT)編譯模式兼容。 預(yù)先編譯能讓你的應(yīng)用加載更快。

另外,你還可以傳入一個普通函數(shù),它要返回一個解析為 ?NgModuleRef?(比如你的 Angular 模塊) 的 Promise。該函數(shù)接收一個額外 ?Providers ?的數(shù)組,這個數(shù)組可以在所返回 ?NgModuleRef ?的 ?Injector ?中可用。 例如,如果你在使用 ?platformBrowser ?或 ?platformBrowserDynamic?,就可以把 ?extraProviders ?數(shù)組傳給它們:

const bootstrapFn = (extraProviders: StaticProvider[]) => {
  const platformRef = platformBrowserDynamic(extraProviders);
  return platformRef.bootstrapModule(MainAngularModule);
};
// or
const bootstrapFn = (extraProviders: StaticProvider[]) => {
  const platformRef = platformBrowser(extraProviders);
  return platformRef.bootstrapModuleFactory(MainAngularModuleFactory);
};

使用 ?NgModuleFactory ?需要更少的樣板代碼,并且是一個很好的默認選項,因為它支持 AOT 開箱即用。 使用自定義函數(shù)需要稍多的代碼,但是給你提供了更大的靈活性。

按需實例化 Angular 模塊

?downgradeModule()? 和 ?UpgradeModule ?之間的另一個關(guān)鍵區(qū)別,就是后者要求你預(yù)先實例化 AngularJS 和 Angular 的模塊。 這意味著你必須為實例化應(yīng)用中的 Angular 而付出代價 —— 即使你以后不會用到任何 Angular 資產(chǎn)。 ?downgradeModule()? 則不那么激進。它只會在第一次用到時才實例化 Angular 部分,也就是說,當(dāng)它需要實例化一個降級后的組件時。

你還可以更進一步,甚至不必將應(yīng)用程序中 Angular 部分的代碼下載到用戶的瀏覽器中 —— 直到需要它的那一刻。 當(dāng)不需要初始渲染或用戶尚未訪問到混合式應(yīng)用中的 Angular 部分時,這特別有用。

舉一些例子:

  • 你只想在特定的路由上使用 Angular,除非用戶訪問此路由,否則你不需要它。
  • 你可以將 Angular 用于僅對特定類型的用戶可見的特性,比如:登錄用戶、管理員或 VIP 成員。這樣在用戶通過了身份驗證之前,你都無需加載 Angular。
  • 你可以把 Angular 用于應(yīng)用中那些在初始渲染時不太重要的特性,并且愿意為了更好地初始加載性能,而忍受加載該特性時的一點延遲。

通過 downgradeModule() 啟動

你可能已經(jīng)猜到了,你不需要修改引導(dǎo)現(xiàn)有 AngularJS 應(yīng)用的方式。?UpgradeModule ?需要一些額外的步驟,但 ?downgradeModule()? 能自行引導(dǎo) Angular 模塊,你只要為它提供配方即可。

要開始使用任何 ?upgrade/static? API,你仍然要像在普通 Angular 應(yīng)用中一樣加載 Angular 框架。要想用 SystemJS 做到這一點,你可以遵循升級的準備工作中的指導(dǎo),有選擇的從快速上手項目的 Github 倉庫中復(fù)制代碼。

你還需要用 ?npm install @angular/upgrade --save? 安裝 ?@angular/upgrade? 包,并添加一個指向 ?@angular/upgrade/static? 包的映射:

'@angular/upgrade/static': 'npm:@angular/upgrade/fesm2015/static.mjs',

接下來,創(chuàng)建一個 ?app.module.ts? 文件,并添加如下 ?NgModule ?類:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

@NgModule({
  imports: [
    BrowserModule
  ]
})
export class MainAngularModule {
  // Empty placeholder method to satisfy the `Compiler`.
  ngDoBootstrap() {}
}

這個最小的 ?NgModule ?導(dǎo)入了 ?BrowserModule?,Angular 每個基于瀏覽器的應(yīng)用都會導(dǎo)入該模塊。 它還定義了一個空的 ?ngDoBootstrap()? 方法,來防止 ?Compiler ?返回錯誤。 在這里它是必要的,因為 ?NgModule ?裝飾器上還沒有聲明 ?bootstrap?。

你不用把 ?bootstrap ?聲明加到 ?NgModule ?裝飾器上,因為 AngularJS 擁有應(yīng)用的根組件,并且 ?ngUpgrade ?會負責(zé)啟動必要的組件。

現(xiàn)在你可以用 ?downgradeModule()? 把 AngularJS 和 Angular 的模塊聯(lián)結(jié)在一起。

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { downgradeModule } from '@angular/upgrade/static';

const bootstrapFn = (extraProviders: StaticProvider[]) => {
  const platformRef = platformBrowserDynamic(extraProviders);
  return platformRef.bootstrapModule(MainAngularModule);
};
const downgradedModule = downgradeModule(bootstrapFn);

angular.module('mainAngularJsModule', [
  downgradedModule
]);

現(xiàn)有的 AngularJS 代碼仍然在和以前一樣正常工作,但你已經(jīng)可以開始添加新的 Angular 代碼了。

使用組件與可注入對象

?downgradeModule()? 和 ?UpgradeModule ?之間的區(qū)別就是這些。 其余的 ?upgrade/static? API 和概念的工作方式在不同的混合式應(yīng)用中都完全一樣了。 

雖然可以降級可注入對象,但在實例化 Angular 模塊之前,無法使用降級后的可注入對象。 安全起見,你需要確保降級后的可注入對象不會用于應(yīng)用中不受 Angular 控制的任何地方。
比如,在只使用 Angular 組件的已升級組件中可以使用降級后的服務(wù),但是,不能在那些不依賴 Angular 的 AngularJS 組件中使用它,也不能從其它模塊中使用降級過的 Angular 組件。

使用混合式應(yīng)用進行預(yù)先編譯

你可以像在任何其它 Angular 應(yīng)用中一樣,利用混合式應(yīng)用的預(yù)先(AOT)編譯功能。 混合式應(yīng)用的設(shè)置與預(yù)先(AOT)編譯一章所講的大致相同,但 ?index.html? 和 ?main-aot.ts? 略有差異。

AOT 需要在 AngularJS 的 ?index.html? 中的 ?<script>? 標簽中加載所有 AngularJS 文件。

你還要將所生成的 ?MainAngularModuleFactory ?傳給 ?downgradeModule()? 函數(shù),而不是自定義引導(dǎo)函數(shù)。

import { downgradeModule } from '@angular/upgrade/static';
import { MainAngularModuleNgFactory } from '../aot/app/app.module.ngfactory';

const downgradedModule = downgradeModule(MainAngularModuleNgFactory);

angular.module('mainAngularJsModule', [
  downgradedModule
]);

這就是當(dāng)你想讓混合式應(yīng)用受益于 AOT 時所要做的一切。

總結(jié)

該頁面介紹了如何借助 ?upgrade/static? 包,來按照你自己的節(jié)奏逐步升級現(xiàn)有的 AngularJS 應(yīng)用。并且升級過程中不會方案此應(yīng)用的進一步開發(fā)。

具體來說,本章介紹了如何使用 ?downgradeModule()? 來代替 ?UpgradeModule?,為混合式應(yīng)用提供更好的性能和更大的靈活性。

總結(jié),?downgradeModule()? 中的關(guān)鍵差異性因素是:

  1. 它允許實例化甚至惰性加載 Angular 部分,這能改善初始加載時間。某些情況下,這可能會完全免除啟動第二個框架的成本。
  2. 通過避免運行不必要的變更檢測,它提高了性能,給開發(fā)人員提供了更大的自定義能力。
  3. 它不需要你更改引導(dǎo) AngularJS 應(yīng)用的方式。

當(dāng)你希望混合式應(yīng)用的 AngularJS 部分和 Angular 部分保持松耦合時,使用 ?downgradeModule()? 是個很好的選擇。 你仍然可以混用并匹配兩個框架中的組件和服務(wù)。作為回報,?downgradeModule()? 為你提供了更大的控制權(quán)和更好的性能。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號