无 Zone 的 Angular 解释 — 在没有 Zone.js 时变更检测的工作原理
Source: Dev.to
Introduction
多年来,Angular 依赖 Zone.js 自动触发变更检测。它能够保持 UI 与数据同步,但也使性能表现难以预测,调试更加困难。现代 Angular——尤其是在引入 Signals 之后——现在可以在没有 Zone.js 的情况下运行。
What Zone.js Actually Did
Zone.js 会对以下异步 API 进行 monkey‑patch:
setTimeoutPromisefetch- DOM 事件
每当发生任何异步操作时,Angular 会自动运行变更检测。这意味着:
- UI 始终保持同步。
- 任意异步事件都可能触发变更检测,即使与当前组件无关。
- 在大型应用中,性能调优变成了猜测。
How Angular Works Without Zone.js
移除 Zone.js 后,Angular 不再在每个异步事件上自动运行变更检测。相反,你需要 显式告知 Angular 应用状态已改变。变更检测仅在 Angular 知道数据已改变时运行,方式包括:
- Signals
- 输入属性的变化
- 显式触发(例如
ChangeDetectorRef)
Signals Overview
Signals 是一种响应式原语,能够让 Angular 自动追踪依赖关系。
// signal.ts
import { signal, computed, effect } from '@angular/core';
export class CounterComponent {
count = signal(0);
increment() {
this.count.update(v => v + 1);
}
doubleCount = computed(() => this.count() * 2);
constructor() {
effect(() => {
console.log('Count changed:', this.count());
});
}
}
Count: {{ count() }}
Double: {{ doubleCount() }}
- Signal 更新:Angular 精确知道哪些内容改变,只重新渲染受影响的视图。
- 没有全局变更检测:不再依赖 Zone.js。
Comparing the Old Zone‑Based Approach with the Zoneless Approach
Zone‑Based Example
// old.component.ts
setTimeout(() => {
this.value = 10; // Angular had to guess when to update the UI
}, 1000);
Zoneless Example Using Signals
// new.component.ts
value = signal(0);
setTimeout(() => {
this.value.set(10); // Signal update → Angular reacts → UI updates
}, 1000);
Bootstrapping Without Zone.js
import { bootstrapApplication } from '@angular/platform-browser';
import { provideZoneChangeDetection } from '@angular/core';
bootstrapApplication(AppComponent, {
providers: [
provideZoneChangeDetection({
eventCoalescing: true,
runCoalescing: true
})
]
});
要彻底移除 Zone.js:
- 删除项目中的
zone.js引入。 - 使用 signals 和显式触发器来处理状态变化。
- 如有需要,可调用
ChangeDetectorRef方法进行手动变更检测。
即使没有 Zone.js,Angular 仍然通过以下方式保持响应式:
- Signal 更新
- 输入绑定
- 事件处理器
- 手动
ChangeDetectorRef调用
When to Go Zoneless
- 大型应用:确定性的渲染和更少的无关重绘让性能调试更容易。
- 使用大量 RxJS 的旧项目:需要权衡利弊;Zoneless 是可选的,而非强制。
Benefits of the Zoneless + Signals Model
- 确定性渲染 – 仅在数据实际改变的地方进行更新。
- 更少的重绘 – 提升运行时性能。
- 更易的性能调试 – 没有隐藏的 Zone.js 副作用。
- 现代响应式思维模型 – 与函数式响应式编程概念保持一致。
Conclusion
Zoneless Angular 并不是在剥离功能,而是去除猜测。
- Zone.js 提供了自动但嘈杂的变更检测。
- Signals + 显式触发器 为你带来明确、快速且可预测的更新。
你并不需要在所有地方都完全去除 Zone.js,但了解其工作原理会让你成为更好的 Angular 开发者。