# 解决区域(Zone)污染

Zone.js是一种信号机制,Angular 用它来检测应用程序状态何时可能已更改。它捕获异步操作,比如 setTimeout、网络请求和事件侦听器。Angular 会根据来自 Zone.js 的信号安排变更检测

Zone.jsis a signaling mechanism that Angular uses to detect when an application state might have changed. It captures asynchronous operations like setTimeout, network requests, and event listeners. Angular schedules change detection based on signals from Zone.js

在某些情况下,已安排的任务或微任务不会对数据模型进行任何更改,这使得运行变更检测变得不必要。常见的例子是:

  • requestAnimationFramesetTimeoutsetInterval

  • 第三方库的任务或微任务调度

本节介绍如何识别此类条件,以及如何在 Angular 区域外运行代码以避免不必要的变更检测调用。

# 识别不必要的变更检测调用

你可以用 Angular DevTools 检测不必要的变更检测调用。它们通常在分析器的时间线中显示为连续的条形,其源为 setTimeoutsetIntervalrequestAnimationFrame或事件处理程序。当你在应用程序中对这些 API 的调用有限时,变更检测调用通常是由第三方库引起的。

Angular DevTools profiler preview showing Zone pollution 在上图中,有一系列由与元素关联的事件处理程序触发的变更检测调用。这是使用第三方非原生 Angular 组件时的常见挑战,这些组件不会更改 NgZone的默认行为。

#NgZone之外运行任务

在这种情况下,你可以指示 Angular 避免使用NgZone为给定代码段调度的任务调用变更检测。

import { Component, NgZone, OnInit } from '@angular/core';
@Component(...)
class AppComponent implements OnInit {
  constructor(private ngZone: NgZone) {}
  ngOnInit() {
    this.ngZone.runOutsideAngular(() => setInterval(pollForUpdates), 500);
  }
}

上面的代码段告诉 Angular 要在 Angular Zone 之外执行 setInterval调用,并在 pollForUpdates运行之后跳过运行变更检测。

第三方库通常会触发不必要的变更检测周期,因为它们在创作时并没有考虑到 Zone.js。通过调用 Angular 区域外的库 API 来避免这些额外的周期:

import { Component, NgZone, OnInit } from '@angular/core';
import * as Plotly from 'plotly.js-dist-min';

@Component(...)
class AppComponent implements OnInit {
  constructor(private ngZone: NgZone) {}
  ngOnInit() {
    this.ngZone.runOutsideAngular(() => {
      Plotly.newPlot('chart', data);
    });
  }
}

runOutsideAngular中运行 Plotly.newPlot('chart', data);会告诉框架它不应该在执行此初始化逻辑安排的这些任务之后执行变更检测。

比如,如果 Plotly.newPlot('chart', data)将事件侦听器添加到 DOM 元素,则 Angular 将不会在执行其处理程序之后执行变更检测。

Last Updated: 5/5/2023, 9:06:42 AM