工作学习总结--angular中的NgZone的简单使用

在Angular中,模板中有一些变量在组件中经常变动,例如变量num:

<div>
  经常变动的数字: {{ num }}
</div>

在组件中它的初始值设定为0

 num = 0;

假设在组件中有个循环,不断更新num的值,每5秒给num加1。

for (let i = 0; i < 100; i++) {
    setInterval(() => this.num++, 5000);
 }

那么频繁的变动将造成性能损耗。
Angular为我们提供了NgZone服务,对于一些频繁的操作,可以不去触发变更检测。

合理使用 ngZone runOutsideAngular 来提升应用性能
我们知道Angular可以自动处理变化检测,这是因为它使用了 zone.js ,简单的来说, zone.js 就是通过打补丁的方式来拦截浏览器的事件,然后进行变化检测,但是变化检测是极其消耗资源的,如果绑定了大量的事件,那么就会造成性能问题,所以我们可以使用 runOutsideAngular 来减少不必要的变化检测。

this.ngZone.runOutsideAngular(() => {
   this.renderer.listen(this.elementRef.nativeElement, 'keydown', event => {
      const keyCode = event.which || event.keyCode;
         if (keyCode === keycodes.ENTER) {
              event.preventDefault();
              this.ngZone.run(() => {
                  this.thyEnter.emit(event);
              });
         }
   });
});

上面这段代码是绑定一个回车事件,如果不使用 runOutsideAngular 的话,只要触发键盘输入事件,就会执行变化检测,这时候我们可以用 runOutsideAngular 在只有为enter事件的时候,去调用 ngZone.run() 主动触发变化检测

NgZone

NgZone是基于Zone来实现的,NgZone从Zone中fork了一份实例,是Zone派生出的一个子Zone,在Angular环境内注册的异步事件都运行在这个子Zone上.

在Angular源码中,有一个ApplicationRef类,其作用是用来监听ngZone中的onTurnDone事件,不论何时只要触发这个事件,那么将会执行
一个tick()方法用来告诉Angular去执行变化监测。

// very simplified version of actual source
class ApplicationRef {
  changeDetectorRefs:ChangeDetectorRef[] = [];

  constructor(private zone: NgZone) {
    this.zone.onTurnDone
      .subscribe(() => this.zone.run(() => this.tick());
  }

  tick() {
    this.changeDetectorRefs
      .forEach((ref) => ref.detectChanges());
  }
}

知道了Angular环境内注册的异步事件都运行在这个NgZone上.下面使用一下runOutsideAngular方法

下面是一个DEMO

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

@Component({
  selector: 'app-root',
  templateUrl: '<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 AppComponent {
  progress: number = 0;
 label: string;
  constructor(private _ngZone: NgZone) {}
  processWithinAngularZone() {
    this.label = 'inside';
     this.progress = 0;
      this._increaseProgress(() => console.log('Inside Done!'));
    }
  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();
     }
   }
}

点击Process within Angular zone会因为双向绑定Progress会从1%持续变到100%.
而点击Process outside of Angular zone 只会显示1%直接到100%.

在这里插入图片描述
感谢这篇博客的帮助Angular 6 动态加载组件显示 NgZone runOutsideAngular

发布了130 篇原创文章 · 获赞 103 · 访问量 26万+

猜你喜欢

转载自blog.csdn.net/xiaolinlife/article/details/100175911