工作学习总结--angular中的NgZone的简单使用
在Angular中,模板中有一些变量在组件中经常变动,例如变量num:<div>经常变动的数字: {{ num }}</div>在组件中它的初始值设定为0num = 0;假设在组件中有个循环,不断更新num的值,每5秒给num加1。for (let i = 0; i < 100; i++) {setInterval(() => ...
在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%.
更多推荐
所有评论(0)