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,125 +185,94 @@ 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); }
}
/**
* Notifies when code enters Angular Zone. This gets fired first on VM Turn. interface NgZonePrivate extends NgZone {
*/ _outer: Zone;
get onUnstable(): EventEmitter<any> { return this._onUnstable; } _inner: Zone;
_nesting: number;
/**
* Notifies when there is no more microtasks enqueue in the current VM Turn. hasPendingMicrotasks: boolean;
* This is a hint for Angular to do change detection, which may enqueue more microtasks. hasPendingMacrotasks: boolean;
* For this reason this event can fire multiple times per VM Turn. isStable: boolean;
*/ }
get onMicrotaskEmpty(): EventEmitter<any> { return this._onMicrotaskEmpty; }
function checkStable(zone: NgZonePrivate) {
/** if (zone._nesting == 0 && !zone.hasPendingMicrotasks && !zone.isStable) {
* Notifies when the last `onMicrotaskEmpty` has run and there are no more microtasks, which try {
* implies we are about to relinquish VM turn. zone._nesting++;
* This event gets called just once. zone.onMicrotaskEmpty.emit(null);
*/ } finally {
get onStable(): EventEmitter<any> { return this._onStable; } zone._nesting--;
if (!zone.hasPendingMicrotasks) {
/** try {
* Notify that an error has been delivered. zone.runOutsideAngular(() => zone.onStable.emit(null));
*/ } finally {
get onError(): EventEmitter<any> { return this._onErrorEvents; } zone.isStable = true;
}
/** }
* Whether there are no outstanding microtasks or macrotasks. }
*/ }
get isStable(): boolean { return this._isStable; } }
get hasPendingMicrotasks(): boolean { return this._hasPendingMicrotasks; } function forkInnerZoneWithAngularBehavior(zone: NgZonePrivate) {
zone._inner = zone._inner.fork({
get hasPendingMacrotasks(): boolean { return this._hasPendingMacrotasks; } name: 'angular',
properties: <any>{'isAngularZone': true},
private checkStable() { onInvokeTask: (delegate: ZoneDelegate, current: Zone, target: Zone, task: Task, applyThis: any,
if (this._nesting == 0 && !this._hasPendingMicrotasks && !this._isStable) { applyArgs: any): any => {
try { try {
this._nesting++; onEnter(zone);
this._onMicrotaskEmpty.emit(null); return delegate.invokeTask(target, task, applyThis, applyArgs);
} finally { } finally {
this._nesting--; onLeave(zone);
if (!this._hasPendingMicrotasks) { }
try { },
this.runOutsideAngular(() => this._onStable.emit(null));
} finally {
this._isStable = true; onInvoke: (delegate: ZoneDelegate, current: Zone, target: Zone, callback: Function,
} applyThis: any, applyArgs: any[], source: string): any => {
} try {
} onEnter(zone);
} return delegate.invoke(target, callback, applyThis, applyArgs, source);
} } finally {
onLeave(zone);
private forkInnerZoneWithAngularBehavior() { }
this.inner = this.inner.fork({ },
name: 'angular',
properties: <any>{'isAngularZone': true}, onHasTask:
onInvokeTask: (delegate: ZoneDelegate, current: Zone, target: Zone, task: Task, (delegate: ZoneDelegate, current: Zone, target: Zone, hasTaskState: HasTaskState) => {
applyThis: any, applyArgs: any): any => { delegate.hasTask(target, hasTaskState);
try { if (current === target) {
this.onEnter(); // We are only interested in hasTask events which originate from our zone
return delegate.invokeTask(target, task, applyThis, applyArgs); // (A child hasTask event is not interesting to us)
} finally { if (hasTaskState.change == 'microTask') {
this.onLeave(); zone.hasPendingMicrotasks = hasTaskState.microTask;
} checkStable(zone);
}, } else if (hasTaskState.change == 'macroTask') {
zone.hasPendingMacrotasks = hasTaskState.macroTask;
}
onInvoke: (delegate: ZoneDelegate, current: Zone, target: Zone, callback: Function, }
applyThis: any, applyArgs: any[], source: string): any => { },
try {
this.onEnter(); onHandleError: (delegate: ZoneDelegate, current: Zone, target: Zone, error: any): boolean => {
return delegate.invoke(target, callback, applyThis, applyArgs, source); delegate.handleError(target, error);
} finally { zone.onError.emit(error);
this.onLeave(); return false;
} }
}, });
}
onHasTask:
(delegate: ZoneDelegate, current: Zone, target: Zone, hasTaskState: HasTaskState) => { function onEnter(zone: NgZonePrivate) {
delegate.hasTask(target, hasTaskState); zone._nesting++;
if (current === target) { if (zone.isStable) {
// We are only interested in hasTask events which originate from our zone zone.isStable = false;
// (A child hasTask event is not interesting to us) zone.onUnstable.emit(null);
if (hasTaskState.change == 'microTask') { }
this.setHasMicrotask(hasTaskState.microTask); }
} else if (hasTaskState.change == 'macroTask') {
this.setHasMacrotask(hasTaskState.macroTask); function onLeave(zone: NgZonePrivate) {
} zone._nesting--;
} checkStable(zone);
},
onHandleError: (delegate: ZoneDelegate, current: Zone, target: Zone, error: any): boolean => {
delegate.handleError(target, error);
this.triggerError(error);
return false;
}
});
}
private onEnter() {
this._nesting++;
if (this._isStable) {
this._isStable = false;
this._onUnstable.emit(null);
}
}
private onLeave() {
this._nesting--;
this.checkStable();
}
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(); }