問題背景

在 Angular 的 HTML 模板中,

我們常常會使用屬性綁定來動態調整元素的屬性,

例如:

<div [style.width]="getWidth()"></div>

這種方式讓我們可以根據程式的狀態或用戶的互動來動態調整元素的寬度,

但是當畫面有變動時 Angular 的變更檢測機制會重新評估模板中的 所有 綁定表達式,

其中也包括函數調用,

這意味著如果在模板中使用了 [style.width]="getWidth()",

每次變更檢測運行時,

getWidth() 函數都會被呼叫,

雖然這種行為在大多數情況下不會導致顯著的性能問題,

但如果 getWidth() 函數的計算成本很高,

或者它被頻繁地調用,

這可能會導致性能下降,

為了避免這種情況,

可以採用以下幾種策略

使用變數而非函數

可以將 getWidth() 的結果存儲在一個變數中,

並在需要時更新這個變數,

只有在變數的值真正改變時,

Angular 才會重新評估綁定表達式

<div [style.width]="width"></div>
width: string = "100px";

使用 Observable 和 async 管道

如果 getWidth() 的結果來自於异步操作(Ex: HTTP request),

可以使用 Observable & async 管道來自動處理變更檢測,

只有當 Observable 發出新的值時,

Angular 才會更新綁定的屬性

<div [style.width]="width$ | async"></div>
width$: Observable<string> = this.http.get("...");

使用 OnPush 變更檢測策略

可以將組件的變更檢測策略設置為 ChangeDetectionStrategy.OnPush.

Angular 只會在 輸入屬性改變者事件觸發時 才進行變更檢測,

而不是在每次變更檢測運行時都重新評估所有綁定表達式

@Component({
  selector: "app-my-component",
  templateUrl: "./my-component.component.html",
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MyComponent {}

使用 trackBy 函數

如果我們在模板中使用 *ngFor 來迭代一個列表,

並且每次變更檢測都會重新生成 DOM 元素,

我們可以使用 `trackBy`` 函數來提高性能,

trackBy 函數可以告訴 Angular 如何追蹤列表中的項目,

從而避免不必要的 DOM 操作

<div *ngFor="let item of items; trackBy: trackByFn">{{ item }}</div>
trackByFn(index: number, item: any): number {
  return item.id;
}

總結

這些策略可以幫助我們優化 Angular 應用程式的性能,

特別是在處理大量數據或進行頻繁的 DOM 操作時,

我們可以根據具體情況選擇適合的策略,

並根據具體需求進行調整,

可以幫助我們避免不必要的性能問題

參考