基礎 signal
Angular 16 加入了 signal 功能,在 Angular 17 部分穩定。
signal 是一個帶值的容器,當容器內的值發生改變時會通知 Angular,Angular 隨即更新所有使用到此 signal 的 UI 部分。此概念類似 Vue.js 的 ref。
基本用法
透過
()
設定預設值:
selectedUser = signal(DUMMY_USERS[randomIndex]);
透過
.set
改變值:
this.selectedUser.set(DUMMY_USERS[randomIndex])
在 HTML 中使用
在 html 中不能作為屬性或變數調用,需作為函數調用以取得最新值(類似 Vue.js 的 ref 需透過 .value 取值)。
一般寫法:
<span>{{ selectedUser.name }}</span>
signal 寫法:
<span>{{ selectedUser().name }}</span>
此寫法通知 Angular 在 template 中需要此 signal 的最新值。Angular 於背後執行訂閱,確保值改變時重新渲染 UI。
Zone.js vs Signal
未使用 signal 時,Angular 採用 Zone.js sub-package。它於 Angular 背後設置不可見的分組機制,監聽可能觸發狀態改變的事件。事件觸發時(如用戶點擊按鈕),Angular 遍歷 zone 中的所有 component,確認數據變化並更新 UI。
signal 使 Angular 能避免使用 zone 機制,提升效率。signal 使 UI 能以更精確的方式更新,無需檢查所有可能的事件。
Computed
getter 可改用 computed(computed 為配合 signal 使用的函數)
一般寫法:
get imagePath() {
return 'assets/users/' + this.selectedUser().avatar;
}
使用 computed:
imagePath = computed(() => {
return 'assets/users/' + this.selectedUser().avatar;
});
使用時需作為函數調用,加上 ()
:
<img [src]="imagePath()" [alt]="selectedUser().name">
computed 的優點
Angular 會分析 computed 函數內使用的 signal 值,並向該 signal 訂閱。signal 值變化時執行重新計算,提升效率。不會在每次 component 或 app 變化時重新計算,僅在使用的 signal 改變時執行計算。
提問:signal 的訂閱機制是否比 zone 的遍歷方式更耗效能?
Zone.js vs Signal 效能比較
監聽範圍
所有變更事件
實際使用的值
檢查機制
遍歷所有組件
直接通知相關 UI
更新範圍
可能更新整個應用
僅更新相關部分
計算成本
每次事件均需遍歷
僅在值改變時計算
結論:Signal 的訂閱機制比 Zone.js 的全面檢查更有效率。初始雖需建立訂閱關係,但執行時僅處理需要更新的部分,避免不必要的檢查與計算。
Last updated