ngZone

如果模板中有一些变量需要经常变动,那么频繁的变动将造成性能上的消耗,Angular为我们提供了NgZone服务,对于一些频繁的操作,可以不去触发变更检测。

使得Angular不跟踪变化。

重新跟踪变化  如果此时又想让Angular跟踪foo的变化,用其提供的run方法。

Angular 引入 Zone.js 以处理变更检测。Zone.js 使 angular 可以决定何时需要刷新UI。通常情况下,你不需要关注 Zone.js,因为其一直在正常工作。

简而言之:Zone.js 如何工作

Zone.js 对所有常见的异步 API(setTimeout, setInterval 和 Promise)打上了“补丁” 以追踪所有的异步操作。

Zone

Zone 是一种用于拦截和跟踪异步工作的机制。

Tasks

Zone.js 将会对每一个异步操作创建一个 task。一个 task 运行于一个 Zone 中。

NgZone

通常来说, 在 Angular APP 中,每个 task 都会在 “Angular” Zone 中运行,这个 Zone 被称为 NgZone。一个 Angular APP 中只存在一个 Angular Zone,而变更检测只会由 运行于这个 NgZone 中的异步操作触发。

Root Zone/Forks

在 Zone.js 中 zone 是存在层级关系的,你永远只会从顶层的 zone 进行操作 - 也就是 “root zone”。新的 zone 可以通过 fork root zone 创建。NgZone 也是由 root zone fork 而来。

ZoneSpecs

在 fork 一个 zone 时,一个新的 zone 将会由 ZoneSpec 创建。一个 ZoneSpec 可以只包含一个提供给新 child zone 的名字,也可以包含许多用于拦截特定 Zone/任务事件的钩子函数。

如果你想要了解更多有关于 Zone.js 的工作机制,浏览这个网页。

你并不一定要在 Angular 应用中使用 Zone.js (但是推荐你使用)

Zone.js 可以在 Angular 应用的启动阶段通过设置一个 noop 的 zone 参数以禁用。然而如果你选择在 Angular 中禁用 Zone,那你就必须自己手动控制 UI 刷新的时机(比如通过 ChangeDetectorRef.detectChanges() 函数)。

通常来说,不推荐放弃使用 Zone.js, 因为你放弃了自动化变更检测的便利,但是对于某些自定义元素(Angular elements),使用手动控制的方式就比较合理了。

Angular 对比 AngularJS 在变化检测上由原来的双向检测(父->子,子->父)变为了单向(父->子)。所以每一次变化检测都会确定性地收敛,一般页面即使有几千个组件,变化检测也可以做几毫秒内完成,所以大家开发时很少会遇到性能瓶颈。(即使是AngularJS也很少遇到瓶颈)

https://angular.io/api/core/NgZone#ngzone

class NgZone {
  static isInAngularZone(): boolean
  static assertInAngularZone(): void
  static assertNotInAngularZone(): void
  constructor(__0)
  hasPendingMacrotasks: boolean
  hasPendingMicrotasks: boolean
  isStable: boolean
  onUnstable: EventEmitter<any>
  onMicrotaskEmpty: EventEmitter<any>
  onStable: EventEmitter<any>
  onError: EventEmitter<any>
  run<T>(fn: (...args: any[]) => T, applyThis?: any, applyArgs?: any[]): T
  runTask<T>(fn: (...args: any[]) => T, applyThis?: any, applyArgs?: any[], name?: string): T
  runGuarded<T>(fn: (...args: any[]) => T, applyThis?: any, applyArgs?: any[]): T
  runOutsideAngular<T>(fn: (...args: any[]) => T): T
}

Example:

import {Component, NgZone} from '@angular/core';
import {NgIf} from '@angular/common';

@Component({
  selector: 'ng-zone-demo',
  template: `
    <h2>Demo: NgZone</h2>

    <p>Progress: {{progress}}%</p>
    <p *ngIf="progress >= 100">Done processing {{label}} of Angular zone!</p>

    <button (click)="processWithinAngularZone()">Process within Angular zone</button>
    <button (click)="processOutsideOfAngularZone()">Process outside of Angular zone</button>
  `,
})
export class NgZoneDemo {
  progress: number = 0;
  label: string;

  constructor(private _ngZone: NgZone) {}

  // Loop inside the Angular zone
  // so the UI DOES refresh after each setTimeout cycle
  processWithinAngularZone() {
    this.label = 'inside';
    this.progress = 0;
    this._increaseProgress(() => console.log('Inside Done!'));
  }

  // Loop outside of the Angular zone
  // so the UI DOES NOT refresh after each setTimeout cycle
  processOutsideOfAngularZone() {
    this.label = 'outside';
    this.progress = 0;
    this._ngZone.runOutsideAngular(() => {
      this._increaseProgress(() => {
        // reenter the Angular zone and display done
        this._ngZone.run(() => { console.log('Outside Done!'); });
      });
    });
  }

  _increaseProgress(doneCallback: () => void) {
    this.progress += 1;
    console.log(`Current progress: ${this.progress}%`);

    if (this.progress < 100) {
      window.setTimeout(() => this._increaseProgress(doneCallback), 10);
    } else {
      doneCallback();
    }
  }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值