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
*/
export class NgZone {
private outer: Zone;
private inner: Zone;
readonly hasPendingMicrotasks: boolean = false;
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;
private _onUnstable: EventEmitter<any> = new EventEmitter(false);
private _onMicrotaskEmpty: EventEmitter<any> = new EventEmitter(false);
private _onStable: EventEmitter<any> = new EventEmitter(false);
private _onErrorEvents: EventEmitter<any> = new EventEmitter(false);
/**
* Notifies when code enters Angular Zone. This gets fired first on VM Turn.
*/
readonly onUnstable: 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}) {
if (typeof Zone == 'undefined') {
@ -103,18 +122,20 @@ export class NgZone {
}
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']) {
this.inner = this.inner.fork((Zone as any)['wtfZoneSpec']);
self._inner = self._inner.fork((Zone as any)['wtfZoneSpec']);
}
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; }
@ -124,6 +145,7 @@ export class NgZone {
throw new Error('Expected to be in Angular Zone, but it is not!');
}
}
static assertNotInAngularZone(): void {
if (NgZone.isInAngularZone()) {
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`.
*/
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
* 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
@ -163,125 +185,94 @@ export class NgZone {
*
* 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); }
/**
* Notifies when code enters Angular Zone. This gets fired first on VM Turn.
*/
get onUnstable(): EventEmitter<any> { return this._onUnstable; }
/**
* 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.
*/
get onMicrotaskEmpty(): EventEmitter<any> { return this._onMicrotaskEmpty; }
/**
* 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.
*/
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 {
this._nesting++;
this._onMicrotaskEmpty.emit(null);
} finally {
this._nesting--;
if (!this._hasPendingMicrotasks) {
try {
this.runOutsideAngular(() => this._onStable.emit(null));
} finally {
this._isStable = true;
}
}
}
}
}
private forkInnerZoneWithAngularBehavior() {
this.inner = this.inner.fork({
name: 'angular',
properties: <any>{'isAngularZone': true},
onInvokeTask: (delegate: ZoneDelegate, current: Zone, target: Zone, task: Task,
applyThis: any, applyArgs: any): any => {
try {
this.onEnter();
return delegate.invokeTask(target, task, applyThis, applyArgs);
} finally {
this.onLeave();
}
},
onInvoke: (delegate: ZoneDelegate, current: Zone, target: Zone, callback: Function,
applyThis: any, applyArgs: any[], source: string): any => {
try {
this.onEnter();
return delegate.invoke(target, callback, applyThis, applyArgs, source);
} finally {
this.onLeave();
}
},
onHasTask:
(delegate: ZoneDelegate, current: Zone, target: Zone, hasTaskState: HasTaskState) => {
delegate.hasTask(target, hasTaskState);
if (current === target) {
// We are only interested in hasTask events which originate from our zone
// (A child hasTask event is not interesting to us)
if (hasTaskState.change == 'microTask') {
this.setHasMicrotask(hasTaskState.microTask);
} else if (hasTaskState.change == 'macroTask') {
this.setHasMacrotask(hasTaskState.macroTask);
}
}
},
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); }
runOutsideAngular(fn: () => any): any { return (this as any as NgZonePrivate)._outer.run(fn); }
}
interface NgZonePrivate extends NgZone {
_outer: Zone;
_inner: Zone;
_nesting: number;
hasPendingMicrotasks: boolean;
hasPendingMacrotasks: boolean;
isStable: boolean;
}
function checkStable(zone: NgZonePrivate) {
if (zone._nesting == 0 && !zone.hasPendingMicrotasks && !zone.isStable) {
try {
zone._nesting++;
zone.onMicrotaskEmpty.emit(null);
} finally {
zone._nesting--;
if (!zone.hasPendingMicrotasks) {
try {
zone.runOutsideAngular(() => zone.onStable.emit(null));
} finally {
zone.isStable = true;
}
}
}
}
}
function forkInnerZoneWithAngularBehavior(zone: NgZonePrivate) {
zone._inner = zone._inner.fork({
name: 'angular',
properties: <any>{'isAngularZone': true},
onInvokeTask: (delegate: ZoneDelegate, current: Zone, target: Zone, task: Task, applyThis: any,
applyArgs: any): any => {
try {
onEnter(zone);
return delegate.invokeTask(target, task, applyThis, applyArgs);
} finally {
onLeave(zone);
}
},
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);
}
},
onHasTask:
(delegate: ZoneDelegate, current: Zone, target: Zone, hasTaskState: HasTaskState) => {
delegate.hasTask(target, hasTaskState);
if (current === target) {
// We are only interested in hasTask events which originate from our zone
// (A child hasTask event is not interesting to us)
if (hasTaskState.change == 'microTask') {
zone.hasPendingMicrotasks = hasTaskState.microTask;
checkStable(zone);
} else if (hasTaskState.change == 'macroTask') {
zone.hasPendingMacrotasks = hasTaskState.macroTask;
}
}
},
onHandleError: (delegate: ZoneDelegate, current: Zone, target: Zone, error: any): boolean => {
delegate.handleError(target, error);
zone.onError.emit(error);
return false;
}
});
}
function onEnter(zone: NgZonePrivate) {
zone._nesting++;
if (zone.isStable) {
zone.isStable = false;
zone.onUnstable.emit(null);
}
}
function onLeave(zone: NgZonePrivate) {
zone._nesting--;
checkStable(zone);
}

View File

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

View File

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