Skip to content

Zone.js 如何触发变更检测?

一句话

Zone.js 通过 monkey-patch(猴子补丁)所有浏览器异步 API(setTimeout/Promise/DOM 事件/fetch),在这些操作完成后自动触发 Angular 的变更检测。

Zone.js 做的事

ts
// 伪代码:Zone.js 拦截 setTimeout
const originalSetTimeout = window.setTimeout
window.setTimeout = function(fn, ms) {
  return originalSetTimeout.call(window, () => {
    Angular.runInZone(fn) // 执行回调后触发变更检测
  }, ms)
}

Angular 在以下操作后自动检查变化:

  • setTimeout / setInterval
  • Promise .then / .catch
  • DOM 事件(click / input / submit)
  • fetch / XMLHttpRequest
  • addEventListener

OnPush 策略

ts
@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
})

告诉 Angular:只有输入属性引用变化时才检查这个组件。和 React 的 memo 类似。

三框架对比

AngularReactVue3
触发更新Zone.js 自动(拦截异步)setState 手动ref.value = x 自动
检测粒度组件树(OnPush 缩 subtree)整个子树动态节点级
优化手段OnPush 策略memo / useCallback默认已优化

面试追问

Q: Zone.js 不依赖的话 Angular 还能工作吗? 能用,但需要手动触发变更检测(ChangeDetectorRef.detectChanges())。微前端场景常设置 ngZone: 'noop'

Q: Zone.js 性能影响大吗? patch 的数量有限(几十个 API),影响可以忽略。主要性能开销来自 Angular 的全树检查——这也是 OnPush 存在的原因。