perf(core): refactor NgZone, decrease size by 1.2Kb (#17773)

- Remove getters
- Hide private methods for better property renaming

```
497893 May 31 11:26 core.umd.js
718073 May 31 11:26 core.umd.js.map
217108 May 31 11:26 core.umd.min.js
575092 May 31 11:26 core.umd.min.js.map
```

```
495594 May 31 11:28 core.umd.js
716943 May 31 11:28 core.umd.js.map
215826 May 31 11:28 core.umd.min.js
574401 May 31 11:28 core.umd.min.js.map
```
diff: 1,282
This commit is contained in:
Jason Aden 2017-07-01 10:29:56 -07:00 committed by GitHub
parent d5dc53ead8
commit b479ed9407
3 changed files with 135 additions and 148 deletions

View File

@ -84,18 +84,37 @@ import {EventEmitter} from '../event_emitter';
* @experimental * @experimental
*/ */
export class NgZone { export class NgZone {
private outer: Zone; readonly hasPendingMicrotasks: boolean = false;
private inner: Zone; readonly hasPendingMacrotasks: boolean = false;
private _hasPendingMicrotasks: boolean = false; /**
private _hasPendingMacrotasks: boolean = false; * Whether there are no outstanding microtasks or macrotasks.
*/
readonly isStable: boolean = true;
private _isStable = true; /**
private _nesting: number = 0; * Notifies when code enters Angular Zone. This gets fired first on VM Turn.
private _onUnstable: EventEmitter<any> = new EventEmitter(false); */
private _onMicrotaskEmpty: EventEmitter<any> = new EventEmitter(false); readonly onUnstable: EventEmitter<any> = new EventEmitter(false);
private _onStable: EventEmitter<any> = new EventEmitter(false);
private _onErrorEvents: EventEmitter<any> = new EventEmitter(false); /**
* Notifies when there is no more microtasks enqueue in the current VM Turn.
* This is a hint for Angular to do change detection, which may enqueue more microtasks.
* For this reason this event can fire multiple times per VM Turn.
*/
readonly onMicrotaskEmpty: EventEmitter<any> = new EventEmitter(false);
/**
* Notifies when the last `onMicrotaskEmpty` has run and there are no more microtasks, which
* implies we are about to relinquish VM turn.
* This event gets called just once.
*/
readonly onStable: EventEmitter<any> = new EventEmitter(false);
/**
* Notifies that an error has been delivered.
*/
readonly onError: EventEmitter<any> = new EventEmitter(false);
constructor({enableLongStackTrace = false}) { constructor({enableLongStackTrace = false}) {
if (typeof Zone == 'undefined') { if (typeof Zone == 'undefined') {
@ -103,18 +122,20 @@ export class NgZone {
} }
Zone.assertZonePatched(); Zone.assertZonePatched();
const self = this as any as NgZonePrivate;
self._nesting = 0;
this.outer = this.inner = Zone.current; self._outer = self._inner = Zone.current;
if ((Zone as any)['wtfZoneSpec']) { if ((Zone as any)['wtfZoneSpec']) {
this.inner = this.inner.fork((Zone as any)['wtfZoneSpec']); self._inner = self._inner.fork((Zone as any)['wtfZoneSpec']);
} }
if (enableLongStackTrace && (Zone as any)['longStackTraceZoneSpec']) { if (enableLongStackTrace && (Zone as any)['longStackTraceZoneSpec']) {
this.inner = this.inner.fork((Zone as any)['longStackTraceZoneSpec']); self._inner = self._inner.fork((Zone as any)['longStackTraceZoneSpec']);
} }
this.forkInnerZoneWithAngularBehavior(); forkInnerZoneWithAngularBehavior(self);
} }
static isInAngularZone(): boolean { return Zone.current.get('isAngularZone') === true; } static isInAngularZone(): boolean { return Zone.current.get('isAngularZone') === true; }
@ -124,6 +145,7 @@ export class NgZone {
throw new Error('Expected to be in Angular Zone, but it is not!'); throw new Error('Expected to be in Angular Zone, but it is not!');
} }
} }
static assertNotInAngularZone(): void { static assertNotInAngularZone(): void {
if (NgZone.isInAngularZone()) { if (NgZone.isInAngularZone()) {
throw new Error('Expected to not be in Angular Zone, but it is!'); throw new Error('Expected to not be in Angular Zone, but it is!');
@ -142,13 +164,13 @@ export class NgZone {
* *
* If a synchronous error happens it will be rethrown and not reported via `onError`. * If a synchronous error happens it will be rethrown and not reported via `onError`.
*/ */
run(fn: () => any): any { return this.inner.run(fn); } run(fn: () => any): any { return (this as any as NgZonePrivate)._inner.run(fn); }
/** /**
* Same as `run`, except that synchronous errors are caught and forwarded via `onError` and not * Same as `run`, except that synchronous errors are caught and forwarded via `onError` and not
* rethrown. * rethrown.
*/ */
runGuarded(fn: () => any): any { return this.inner.runGuarded(fn); } runGuarded(fn: () => any): any { return (this as any as NgZonePrivate)._inner.runGuarded(fn); }
/** /**
* Executes the `fn` function synchronously in Angular's parent zone and returns value returned by * Executes the `fn` function synchronously in Angular's parent zone and returns value returned by
@ -163,70 +185,48 @@ export class NgZone {
* *
* Use {@link #run} to reenter the Angular zone and do work that updates the application model. * Use {@link #run} to reenter the Angular zone and do work that updates the application model.
*/ */
runOutsideAngular(fn: () => any): any { return this.outer.run(fn); } runOutsideAngular(fn: () => any): any { return (this as any as NgZonePrivate)._outer.run(fn); }
}
/** interface NgZonePrivate extends NgZone {
* Notifies when code enters Angular Zone. This gets fired first on VM Turn. _outer: Zone;
*/ _inner: Zone;
get onUnstable(): EventEmitter<any> { return this._onUnstable; } _nesting: number;
/** hasPendingMicrotasks: boolean;
* Notifies when there is no more microtasks enqueue in the current VM Turn. hasPendingMacrotasks: boolean;
* This is a hint for Angular to do change detection, which may enqueue more microtasks. isStable: boolean;
* For this reason this event can fire multiple times per VM Turn. }
*/
get onMicrotaskEmpty(): EventEmitter<any> { return this._onMicrotaskEmpty; }
/** function checkStable(zone: NgZonePrivate) {
* Notifies when the last `onMicrotaskEmpty` has run and there are no more microtasks, which if (zone._nesting == 0 && !zone.hasPendingMicrotasks && !zone.isStable) {
* implies we are about to relinquish VM turn.
* This event gets called just once.
*/
get onStable(): EventEmitter<any> { return this._onStable; }
/**
* Notify that an error has been delivered.
*/
get onError(): EventEmitter<any> { return this._onErrorEvents; }
/**
* Whether there are no outstanding microtasks or macrotasks.
*/
get isStable(): boolean { return this._isStable; }
get hasPendingMicrotasks(): boolean { return this._hasPendingMicrotasks; }
get hasPendingMacrotasks(): boolean { return this._hasPendingMacrotasks; }
private checkStable() {
if (this._nesting == 0 && !this._hasPendingMicrotasks && !this._isStable) {
try { try {
this._nesting++; zone._nesting++;
this._onMicrotaskEmpty.emit(null); zone.onMicrotaskEmpty.emit(null);
} finally { } finally {
this._nesting--; zone._nesting--;
if (!this._hasPendingMicrotasks) { if (!zone.hasPendingMicrotasks) {
try { try {
this.runOutsideAngular(() => this._onStable.emit(null)); zone.runOutsideAngular(() => zone.onStable.emit(null));
} finally { } finally {
this._isStable = true; zone.isStable = true;
}
} }
} }
} }
} }
}
private forkInnerZoneWithAngularBehavior() { function forkInnerZoneWithAngularBehavior(zone: NgZonePrivate) {
this.inner = this.inner.fork({ zone._inner = zone._inner.fork({
name: 'angular', name: 'angular',
properties: <any>{'isAngularZone': true}, properties: <any>{'isAngularZone': true},
onInvokeTask: (delegate: ZoneDelegate, current: Zone, target: Zone, task: Task, onInvokeTask: (delegate: ZoneDelegate, current: Zone, target: Zone, task: Task, applyThis: any,
applyThis: any, applyArgs: any): any => { applyArgs: any): any => {
try { try {
this.onEnter(); onEnter(zone);
return delegate.invokeTask(target, task, applyThis, applyArgs); return delegate.invokeTask(target, task, applyThis, applyArgs);
} finally { } finally {
this.onLeave(); onLeave(zone);
} }
}, },
@ -234,10 +234,10 @@ export class NgZone {
onInvoke: (delegate: ZoneDelegate, current: Zone, target: Zone, callback: Function, onInvoke: (delegate: ZoneDelegate, current: Zone, target: Zone, callback: Function,
applyThis: any, applyArgs: any[], source: string): any => { applyThis: any, applyArgs: any[], source: string): any => {
try { try {
this.onEnter(); onEnter(zone);
return delegate.invoke(target, callback, applyThis, applyArgs, source); return delegate.invoke(target, callback, applyThis, applyArgs, source);
} finally { } finally {
this.onLeave(); onLeave(zone);
} }
}, },
@ -248,40 +248,31 @@ export class NgZone {
// We are only interested in hasTask events which originate from our zone // We are only interested in hasTask events which originate from our zone
// (A child hasTask event is not interesting to us) // (A child hasTask event is not interesting to us)
if (hasTaskState.change == 'microTask') { if (hasTaskState.change == 'microTask') {
this.setHasMicrotask(hasTaskState.microTask); zone.hasPendingMicrotasks = hasTaskState.microTask;
checkStable(zone);
} else if (hasTaskState.change == 'macroTask') { } else if (hasTaskState.change == 'macroTask') {
this.setHasMacrotask(hasTaskState.macroTask); zone.hasPendingMacrotasks = hasTaskState.macroTask;
} }
} }
}, },
onHandleError: (delegate: ZoneDelegate, current: Zone, target: Zone, error: any): boolean => { onHandleError: (delegate: ZoneDelegate, current: Zone, target: Zone, error: any): boolean => {
delegate.handleError(target, error); delegate.handleError(target, error);
this.triggerError(error); zone.onError.emit(error);
return false; return false;
} }
}); });
} }
private onEnter() { function onEnter(zone: NgZonePrivate) {
this._nesting++; zone._nesting++;
if (this._isStable) { if (zone.isStable) {
this._isStable = false; zone.isStable = false;
this._onUnstable.emit(null); zone.onUnstable.emit(null);
} }
} }
private onLeave() { function onLeave(zone: NgZonePrivate) {
this._nesting--; zone._nesting--;
this.checkStable(); checkStable(zone);
}
private setHasMicrotask(hasMicrotasks: boolean) {
this._hasPendingMicrotasks = hasMicrotasks;
this.checkStable();
}
private setHasMacrotask(hasMacrotasks: boolean) { this._hasPendingMacrotasks = hasMacrotasks; }
private triggerError(error: any) { this._onErrorEvents.emit(error); }
} }

View File

@ -28,22 +28,20 @@ function microTask(fn: Function): void {
@Injectable() @Injectable()
class MockNgZone extends NgZone { class MockNgZone extends NgZone {
/** @internal */ /** @internal */
_onUnstableStream: EventEmitter<any>; onUnstable: EventEmitter<any>;
get onUnstable() { return this._onUnstableStream; }
/** @internal */ /** @internal */
_onStableStream: EventEmitter<any>; onStable: EventEmitter<any>;
get onStable() { return this._onStableStream; }
constructor() { constructor() {
super({enableLongStackTrace: false}); super({enableLongStackTrace: false});
this._onUnstableStream = new EventEmitter(false); this.onUnstable = new EventEmitter(false);
this._onStableStream = new EventEmitter(false); this.onStable = new EventEmitter(false);
} }
unstable(): void { this._onUnstableStream.emit(null); } unstable(): void { this.onUnstable.emit(null); }
stable(): void { this._onStableStream.emit(null); } stable(): void { this.onStable.emit(null); }
} }
export function main() { export function main() {

View File

@ -14,12 +14,10 @@ import {EventEmitter, Injectable, NgZone} from '@angular/core';
*/ */
@Injectable() @Injectable()
export class MockNgZone extends NgZone { export class MockNgZone extends NgZone {
private _mockOnStable: EventEmitter<any> = new EventEmitter(false); onStable: EventEmitter<any> = new EventEmitter(false);
constructor() { super({enableLongStackTrace: false}); } constructor() { super({enableLongStackTrace: false}); }
get onStable() { return this._mockOnStable; }
run(fn: Function): any { return fn(); } run(fn: Function): any { return fn(); }
runOutsideAngular(fn: Function): any { return fn(); } runOutsideAngular(fn: Function): any { return fn(); }