Skip to content
This repository was archived by the owner on Feb 26, 2024. It is now read-only.

Commit 9f5d2e8

Browse files
committed
update logic and test
1 parent 72e0b9b commit 9f5d2e8

File tree

8 files changed

+129
-130
lines changed

8 files changed

+129
-130
lines changed

karma-build-jasmine-lazy.conf.js

+1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ module.exports = function(config) {
1010
config.client.preload = 'build/test/browser-lazy-zone-setup.js';
1111
require('./karma-build-jasmine.conf.js')(config);
1212
config.client.entrypoint = 'browser_lazy_zone_entry_point';
13+
config.client.notPatchTestFramework = true;
1314
};

lib/browser/browser.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Zone.__load_patch('util', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
2424
api.patchMethod = patchMethod;
2525
api.bindArguments = bindArguments;
2626
api.attachOriginToPatched = attachOriginToPatched;
27-
}, true);
27+
});
2828

2929
Zone.__load_patch('timers', (global: any) => {
3030
const set = 'set';

lib/common/fetch.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Zone.__load_patch('fetch', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
2525
signal.abortController = abortController;
2626
return abortController;
2727
};
28+
global['AbortController'].prototype = OriginalAbortController.prototype;
2829
abortNative = api.patchMethod(
2930
OriginalAbortController.prototype, 'abort',
3031
(delegate: Function) => (self: any, args: any) => {
@@ -97,4 +98,4 @@ Zone.__load_patch('fetch', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
9798
}
9899
});
99100
};
100-
});
101+
});

lib/common/promise.ts

+13-6
Original file line numberDiff line numberDiff line change
@@ -408,12 +408,18 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr
408408
const NativePromise = global[symbolPromise] = global['Promise'];
409409
const ZONE_AWARE_PROMISE = Zone.__symbol__('ZoneAwarePromise');
410410

411-
let desc = ObjectGetOwnPropertyDescriptor(global, 'Promise');
412-
if (!desc || desc.configurable) {
413-
desc && delete desc.writable;
414-
desc && delete desc.value;
415-
if (!desc) {
411+
let desc = null;
412+
const originalDesc = ObjectGetOwnPropertyDescriptor(global, 'Promise');
413+
if (!originalDesc || originalDesc.configurable) {
414+
if (!originalDesc) {
416415
desc = {configurable: true, enumerable: true};
416+
} else {
417+
desc = {
418+
configurable: originalDesc.configurable,
419+
enumerable: originalDesc.enumerable,
420+
get: originalDesc.get,
421+
set: originalDesc.set
422+
};
417423
}
418424
desc.get = function() {
419425
// if we already set ZoneAwarePromise, use patched one
@@ -442,10 +448,11 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr
442448
};
443449

444450
ObjectDefineProperty(global, 'Promise', desc);
451+
(Zone as any).__register_patched_delegate(global, 'Promise', originalDesc, true);
445452
}
446453

447454
global['Promise'] = ZoneAwarePromise;
448-
api.attachOriginToPatched(global, ZONE_AWARE_PROMISE, NativePromise);
455+
api.attachOriginToPatched(global, 'Promise', NativePromise);
449456

450457
const symbolThenPatched = __symbol__('thenPatched');
451458

lib/zone.ts

+13-34
Original file line numberDiff line numberDiff line change
@@ -683,7 +683,7 @@ const Zone: ZoneType = (function(global: any) {
683683
static __symbol__: (name: string) => string = __symbol__;
684684

685685
static assertZonePatched() {
686-
if (patchLoaded && global['Promise'] !== patchedPromise) {
686+
if (global['Promise'] !== patchedPromise) {
687687
throw new Error(
688688
'Zone.js has detected that ZoneAwarePromise `(window|global).Promise` ' +
689689
'has been overwritten.\n' +
@@ -717,39 +717,17 @@ const Zone: ZoneType = (function(global: any) {
717717
_mode = newMode;
718718
}
719719

720-
static __load_patch(name: string, fn: _PatchFn, preload = false): void {
720+
static __load_patch(name: string, fn: _PatchFn): void {
721721
if (patches.hasOwnProperty(name)) {
722722
throw Error('Already loaded patch: ' + name);
723723
} else if (!global['__Zone_disable_' + name]) {
724724
const perfName = 'Zone:' + name;
725725
mark(perfName);
726-
if (_mode === 'normal' || preload) {
727-
patches[name] = fn(global, Zone, _api);
728-
} else {
729-
patches[name] = function() {
730-
return fn(global, Zone, _api);
731-
};
732-
}
726+
patches[name] = fn(global, Zone, _api);
733727
performanceMeasure(perfName, perfName);
734728
}
735729
}
736730

737-
static __load() {
738-
if (patchLoaded) {
739-
return;
740-
}
741-
Object.keys(patches).forEach(key => {
742-
const loadPatchFn = patches[key];
743-
if (typeof loadPatchFn === 'function') {
744-
const r = loadPatchFn();
745-
if (key === 'ZoneAwarePromise') {
746-
patchedPromise = r;
747-
}
748-
}
749-
});
750-
patchLoaded = true;
751-
}
752-
753731
static __register_patched_delegate(
754732
proto: any, property: string, origin: any, isPropertyDesc = false) {
755733
if (!isPropertyDesc) {
@@ -772,7 +750,7 @@ const Zone: ZoneType = (function(global: any) {
772750
}
773751

774752
static __reloadAll() {
775-
if (patchLoaded) {
753+
if (monkeyPatched) {
776754
return;
777755
}
778756
delegates.forEach(delegate => {
@@ -782,11 +760,11 @@ const Zone: ZoneType = (function(global: any) {
782760
delegate.proto[delegate.property] = delegate.patched;
783761
}
784762
});
785-
patchLoaded = true;
763+
monkeyPatched = true;
786764
}
787765

788766
static __unloadAll() {
789-
if (!patchLoaded) {
767+
if (!monkeyPatched) {
790768
return;
791769
}
792770
delegates.forEach(delegate => {
@@ -796,7 +774,7 @@ const Zone: ZoneType = (function(global: any) {
796774
delegate.proto[delegate.property] = delegate.origin;
797775
}
798776
});
799-
patchLoaded = false;
777+
monkeyPatched = false;
800778
}
801779

802780
public get parent(): AmbientZone|null {
@@ -856,7 +834,7 @@ const Zone: ZoneType = (function(global: any) {
856834
public run(callback: Function, applyThis?: any, applyArgs?: any[], source?: string): any;
857835
public run<T>(
858836
callback: (...args: any[]) => T, applyThis?: any, applyArgs?: any[], source?: string): T {
859-
if (!patchLoaded && _mode === 'lazy') {
837+
if (!monkeyPatched && _mode === 'lazy') {
860838
Zone.__reloadAll();
861839
}
862840
_currentZoneFrame = {parent: _currentZoneFrame, zone: this};
@@ -874,7 +852,7 @@ const Zone: ZoneType = (function(global: any) {
874852
public runGuarded<T>(
875853
callback: (...args: any[]) => T, applyThis: any = null, applyArgs?: any[],
876854
source?: string) {
877-
if (!patchLoaded && _mode === 'lazy') {
855+
if (!monkeyPatched && _mode === 'lazy') {
878856
Zone.__reloadAll();
879857
}
880858
_currentZoneFrame = {parent: _currentZoneFrame, zone: this};
@@ -914,7 +892,7 @@ const Zone: ZoneType = (function(global: any) {
914892
task.runCount++;
915893
const previousTask = _currentTask;
916894
_currentTask = task;
917-
if (!patchLoaded && _mode === 'lazy') {
895+
if (!monkeyPatched && _mode === 'lazy') {
918896
Zone.__reloadAll();
919897
}
920898
_currentZoneFrame = {parent: _currentZoneFrame, zone: this};
@@ -1451,7 +1429,7 @@ const Zone: ZoneType = (function(global: any) {
14511429
let patchedPromise: any;
14521430
const delegates:
14531431
{proto: any, property: string, patched: any, origin: any, isPropertyDesc: boolean}[] = [];
1454-
let patchLoaded = false;
1432+
let monkeyPatched = true;
14551433
const _api: _ZonePrivate = {
14561434
symbol: __symbol__,
14571435
currentZoneFrame: () => _currentZoneFrame,
@@ -1472,7 +1450,8 @@ const Zone: ZoneType = (function(global: any) {
14721450
nativeMicroTaskQueuePromise = NativePromise.resolve(0);
14731451
}
14741452
},
1475-
attachOriginToPatched: (patchedTarget: any, prop: string, original: any) => noop
1453+
attachOriginToPatched: (patchedTarget: any, prop: string, original: any) =>
1454+
Zone.__register_patched_delegate(patchedTarget, prop, original)
14761455
};
14771456
let _currentZoneFrame: _ZoneFrame = {parent: null, zone: new Zone(null, null)};
14781457
let _currentTask: Task|null = null;

test/browser/lazy.spec.ts

+36-33
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
describe('lazy', function() {
1010
const targets = [
11-
{proto: 'Window', property: '__zone_symbol__ZoneAwarePromise'},
11+
{proto: 'Window', property: 'Promise'},
1212
{proto: 'Promise', property: 'then'},
1313
{proto: 'AbortController', property: 'abort'},
1414
{proto: 'Window', property: 'setTimeout'},
@@ -29,7 +29,7 @@ describe('lazy', function() {
2929
{proto: 'Window', property: 'WebKitMutationObserver'},
3030
{proto: 'Window', property: 'IntersectionObserver'},
3131
{proto: 'Window', property: 'FileReader'},
32-
{proto: 'HTMLDocument', property: 'registerElement'},
32+
{proto: 'Document', property: 'registerElement'},
3333
{proto: 'CustomElementRegistry', property: 'define'},
3434
{proto: 'HTMLCanvasElement', property: 'toBlob'},
3535
{proto: 'XMLHttpRequest', property: 'open'},
@@ -39,38 +39,41 @@ describe('lazy', function() {
3939
{proto: 'Geolocation', property: 'watchPosition'}
4040
];
4141

42-
it('before patch should use native delegate', (done: DoneFn) => {
43-
const zone = Zone.current.fork({name: 'zone'});
44-
zone.run(() => {
45-
Promise.resolve().then(() => {
46-
expect(Zone.current.name).not.toEqual(zone.name);
47-
});
48-
setTimeout(() => {
49-
expect(Zone.current.name).not.toEqual(zone.name);
50-
});
51-
const interval = setInterval(() => {
52-
expect(Zone.current.name).not.toEqual(zone.name);
53-
clearInterval(interval);
54-
}, 100);
55-
requestAnimationFrame(() => {
56-
expect(Zone.current.name).not.toEqual(zone.name);
57-
});
58-
const btn = document.createElement('button');
59-
document.body.appendChild(btn);
60-
btn.addEventListener('click', () => {
61-
expect(Zone.current.name).not.toEqual(zone.name);
62-
});
63-
const evt = document.createEvent('MouseEvent');
64-
evt.initEvent('click', true, true);
65-
Zone.root.run(() => {
66-
btn.dispatchEvent(evt);
67-
});
68-
setTimeout(done, 500);
42+
function checkDelegates(isNative: boolean) {
43+
targets.forEach(t => {
44+
const protoName = t.proto;
45+
const property = t.property;
46+
let proto = null;
47+
if (protoName === 'Window') {
48+
proto = window;
49+
} else if (protoName === 'Document') {
50+
proto = document;
51+
} else if (protoName === 'CustomElementRegistry') {
52+
proto = window['customElements'];
53+
} else {
54+
proto = (window as any)[protoName] && (window as any)[protoName].prototype;
55+
}
56+
if (proto) {
57+
const native = proto[Zone.__symbol__(property)];
58+
console.log('check target', protoName, property);
59+
if (isNative) {
60+
expect(proto[property]).toBe(native);
61+
} else {
62+
expect(proto[property]).not.toBe(native);
63+
}
64+
}
6965
});
70-
});
66+
}
7167

72-
it('after load should use patched delegate',
73-
(done: DoneFn) => {
68+
it('before patch should use native delegate', (done: DoneFn) => {
69+
(Zone as any).__unloadAll();
70+
checkDelegates(true);
71+
done();
72+
});
7473

75-
});
74+
it('after load should use patched delegate', (done: DoneFn) => {
75+
(Zone as any).__reloadAll();
76+
checkDelegates(false);
77+
done();
78+
});
7679
});

test/browser/performance.spec.ts

+53-51
Original file line numberDiff line numberDiff line change
@@ -5,55 +5,57 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.io/license
77
*/
8+
import {ifEnvSupports} from '../test-util';
89

9-
describe('Performance', () => {
10-
function mark(name: string) {
11-
performance && performance['mark'] && performance['mark'](name);
12-
}
13-
function performanceMeasure(name: string, label: string) {
14-
performance && performance['measure'] && performance['measure'](name, label);
15-
}
16-
function getEntriesByName(name: string) {
17-
return performance && performance['getEntriesByName'] &&
18-
performance['getEntriesByName'](name).filter(m => m.entryType === 'measure');
19-
}
20-
describe('Lazy mode', () => {
21-
const rootZone = Zone.root;
22-
const noop = function() {};
23-
const normal = function() {
24-
for (let i = 0; i < 10000; i++) {
25-
let j = i * i;
26-
}
27-
};
28-
const times = 10000;
29-
describe('root zone performance benchmark', () => {
30-
it('noop function', () => {
31-
const normal = 'rootZone normal noop';
32-
mark(normal);
33-
for (let i = 0; i < times; i++) {
34-
rootZone.run(noop);
35-
}
36-
performanceMeasure(normal, normal);
37-
const normalEntries = getEntriesByName(normal);
38-
const normalDuration = normalEntries[0].duration;
39-
const normalAverage = normalDuration / times;
40-
console.log(`${normal} ${times} times cost: ${normalDuration}, ${normalAverage} average`);
41-
const lazy = 'rootZone lazy noop';
42-
mark(lazy);
43-
(Zone as any).mode = 'lazy';
44-
for (let i = 0; i < times; i++) {
45-
rootZone.run(noop);
46-
}
47-
performanceMeasure(lazy, lazy);
48-
const lazyEntries = getEntriesByName(lazy);
49-
const lazyDuration = lazyEntries[0].duration;
50-
const lazyAverage = lazyDuration / times;
51-
console.log(`${lazy} ${times} times cost: ${lazyDuration}, ${lazyAverage}`);
52-
(Zone as any).mode = 'normal';
53-
const diff = lazyDuration - normalDuration;
54-
const diffAverage = diff / times;
55-
console.log(`diff running ${times} times is: ${diff}, average is ${diffAverage}`);
56-
});
57-
});
58-
});
59-
});
10+
describe('Performance', ifEnvSupports('performance', () => {
11+
function mark(name: string) {
12+
performance && performance['mark'] && performance['mark'](name);
13+
}
14+
function performanceMeasure(name: string, label: string) {
15+
performance && performance['measure'] && performance['measure'](name, label);
16+
}
17+
function getEntriesByName(name: string) {
18+
return performance && performance['getEntriesByName'] &&
19+
performance['getEntriesByName'](name).filter(m => m.entryType === 'measure');
20+
}
21+
describe('Lazy mode', () => {
22+
const rootZone = Zone.root;
23+
const noop = function() {};
24+
const normal = function() {
25+
for (let i = 0; i < 10000; i++) {
26+
let j = i * i;
27+
}
28+
};
29+
const times = 10000;
30+
describe('root zone performance benchmark', () => {
31+
it('noop function', () => {
32+
const normal = 'rootZone normal noop';
33+
mark(normal);
34+
for (let i = 0; i < times; i++) {
35+
rootZone.run(noop);
36+
}
37+
performanceMeasure(normal, normal);
38+
const normalEntries = getEntriesByName(normal);
39+
const normalDuration = normalEntries[0].duration;
40+
const normalAverage = normalDuration / times;
41+
console.log(
42+
`${normal} ${times} times cost: ${normalDuration}, ${normalAverage} average`);
43+
const lazy = 'rootZone lazy noop';
44+
mark(lazy);
45+
(Zone as any).mode = 'lazy';
46+
for (let i = 0; i < times; i++) {
47+
rootZone.run(noop);
48+
}
49+
performanceMeasure(lazy, lazy);
50+
const lazyEntries = getEntriesByName(lazy);
51+
const lazyDuration = lazyEntries[0].duration;
52+
const lazyAverage = lazyDuration / times;
53+
console.log(`${lazy} ${times} times cost: ${lazyDuration}, ${lazyAverage}`);
54+
(Zone as any).mode = 'normal';
55+
const diff = lazyDuration - normalDuration;
56+
const diffAverage = diff / times;
57+
console.log(`diff running ${times} times is: ${diff}, average is ${diffAverage}`);
58+
});
59+
});
60+
});
61+
}));

0 commit comments

Comments
 (0)