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

Commit 8fb3d04

Browse files
committed
pass test
1 parent cb9e872 commit 8fb3d04

File tree

11 files changed

+225
-28
lines changed

11 files changed

+225
-28
lines changed

karma-build-jasmine-lazy.conf.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
module.exports = function(config) {
10+
require('./karma-base-jasmine.conf.js')(config);
11+
config.client.setup = 'browser-lazy-zone-setup';
12+
config.client.entrypoint = 'browser_lazy_zone_entry_point';
13+
};

lib/browser/browser.ts

Lines changed: 1 addition & 1 deletion
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-
});
27+
}, true);
2828

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

lib/common/promise.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,7 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr
445445
}
446446

447447
global['Promise'] = ZoneAwarePromise;
448-
api.attachOriginToPatched(global, 'Promise', NativePromise);
448+
api.attachOriginToPatched(global, ZONE_AWARE_PROMISE, NativePromise);
449449

450450
const symbolThenPatched = __symbol__('thenPatched');
451451

@@ -470,6 +470,7 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr
470470
return wrapped.then(onResolve, onReject);
471471
};
472472
(Ctor as any)[symbolThenPatched] = true;
473+
api.attachOriginToPatched(Ctor.prototype, 'then', originalThen);
473474
}
474475

475476
api.patchThen = patchThen;

lib/common/utils.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,13 +159,23 @@ const wrapFn = function(event: Event) {
159159
};
160160

161161
export function patchProperty(obj: any, prop: string, prototype?: any) {
162-
let desc = ObjectGetOwnPropertyDescriptor(obj, prop);
163-
if (!desc && prototype) {
162+
let desc: PropertyDescriptor | null = null;
163+
const originalDesc = ObjectGetOwnPropertyDescriptor(obj, prop);
164+
if (!originalDesc && prototype) {
164165
// when patch window object, use prototype to check prop exist or not
165166
const prototypeDesc = ObjectGetOwnPropertyDescriptor(prototype, prop);
166167
if (prototypeDesc) {
167168
desc = {enumerable: true, configurable: true};
168169
}
170+
} else if (originalDesc) {
171+
desc = {
172+
configurable: originalDesc.configurable,
173+
enumerable: originalDesc.enumerable,
174+
value: originalDesc.value,
175+
writable: originalDesc.writable,
176+
get: originalDesc.get,
177+
set: originalDesc.set
178+
};
169179
}
170180
// if the descriptor not exists or is not configurable
171181
// just return
@@ -262,6 +272,8 @@ export function patchProperty(obj: any, prop: string, prototype?: any) {
262272
ObjectDefineProperty(obj, prop, desc);
263273

264274
obj[onPropPatchedSymbol] = true;
275+
276+
(Zone as any).__register_patched_delegate(obj, prop, originalDesc, true);
265277
}
266278

267279
export function patchOnProperties(obj: any, properties: string[]|null, prototype?: any) {
@@ -485,6 +497,7 @@ export function patchMicroTask(
485497

486498
export function attachOriginToPatched(patchedTarget: any, prop: string, original: any) {
487499
patchedTarget[prop][zoneSymbol('OriginalDelegate')] = original;
500+
(Zone as any).__register_patched_delegate(patchedTarget, prop, original);
488501
}
489502

490503
let isDetectedIEOrEdge = false;

lib/zone.ts

Lines changed: 86 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ interface Zone {
154154
* @returns {any} The value for the key, or `undefined` if not found.
155155
*/
156156
get(key: string): any;
157+
157158
/**
158159
* Returns a Zone which defines a `key`.
159160
*
@@ -163,13 +164,15 @@ interface Zone {
163164
* @returns {Zone} The Zone which defines the `key`, `null` if not found.
164165
*/
165166
getZoneWith(key: string): Zone|null;
167+
166168
/**
167169
* Used to create a child zone.
168170
*
169171
* @param zoneSpec A set of rules which the child zone should follow.
170172
* @returns {Zone} A new child zone.
171173
*/
172174
fork(zoneSpec: ZoneSpec): Zone;
175+
173176
/**
174177
* Wraps a callback function in a new function which will properly restore the current zone upon
175178
* invocation.
@@ -184,6 +187,7 @@ interface Zone {
184187
* @returns {function(): *} A function which will invoke the `callback` through [Zone.runGuarded].
185188
*/
186189
wrap<F extends Function>(callback: F, source: string): F;
190+
187191
/**
188192
* Invokes a function in a given zone.
189193
*
@@ -196,6 +200,7 @@ interface Zone {
196200
* @returns {any} Value from the `callback` function.
197201
*/
198202
run<T>(callback: Function, applyThis?: any, applyArgs?: any[], source?: string): T;
203+
199204
/**
200205
* Invokes a function in a given zone and catches any exceptions.
201206
*
@@ -211,6 +216,7 @@ interface Zone {
211216
* @returns {any} Value from the `callback` function.
212217
*/
213218
runGuarded<T>(callback: Function, applyThis?: any, applyArgs?: any[], source?: string): T;
219+
214220
/**
215221
* Execute the Task by restoring the [Zone.currentTask] in the Task's zone.
216222
*
@@ -303,7 +309,7 @@ interface ZoneType {
303309
root: Zone;
304310

305311
/** @internal */
306-
__load_patch(name: string, fn: _PatchFn): void;
312+
__load_patch(name: string, fn: _PatchFn, preload?: boolean): void;
307313

308314
/** @internal */
309315
__symbol__(name: string): string;
@@ -488,14 +494,22 @@ interface ZoneSpec {
488494
*/
489495
interface ZoneDelegate {
490496
zone: Zone;
497+
491498
fork(targetZone: Zone, zoneSpec: ZoneSpec): Zone;
499+
492500
intercept(targetZone: Zone, callback: Function, source: string): Function;
501+
493502
invoke(targetZone: Zone, callback: Function, applyThis?: any, applyArgs?: any[], source?: string):
494503
any;
504+
495505
handleError(targetZone: Zone, error: any): boolean;
506+
496507
scheduleTask(targetZone: Zone, task: Task): Task;
508+
497509
invokeTask(targetZone: Zone, task: Task, applyThis?: any, applyArgs?: any[]): any;
510+
498511
cancelTask(targetZone: Zone, task: Task): any;
512+
499513
hasTask(targetZone: Zone, isEmpty: HasTaskState): void;
500514
}
501515

@@ -637,12 +651,15 @@ type AmbientZoneDelegate = ZoneDelegate;
637651
const Zone: ZoneType = (function(global: any) {
638652
const performance: {mark(name: string): void; measure(name: string, label: string): void;} =
639653
global['performance'];
654+
640655
function mark(name: string) {
641656
performance && performance['mark'] && performance['mark'](name);
642657
}
658+
643659
function performanceMeasure(name: string, label: string) {
644660
performance && performance['measure'] && performance['measure'](name, label);
645661
}
662+
646663
mark('Zone');
647664
if (global['Zone']) {
648665
// if global['Zone'] already exists (maybe zone.js was already loaded or
@@ -666,7 +683,7 @@ const Zone: ZoneType = (function(global: any) {
666683
static __symbol__: (name: string) => string = __symbol__;
667684

668685
static assertZonePatched() {
669-
if (global['Promise'] !== patches['ZoneAwarePromise']) {
686+
if (patchLoaded && global['Promise'] !== patchedPromise) {
670687
throw new Error(
671688
'Zone.js has detected that ZoneAwarePromise `(window|global).Promise` ' +
672689
'has been overwritten.\n' +
@@ -692,42 +709,92 @@ const Zone: ZoneType = (function(global: any) {
692709
return _currentTask;
693710
}
694711

695-
static __load_patch(name: string, fn: _PatchFn): void {
712+
static get mode(): 'lazy'|'normal' {
713+
return _mode;
714+
}
715+
716+
static set mode(newMode: 'lazy'|'normal') {
717+
_mode = newMode;
718+
}
719+
720+
static __load_patch(name: string, fn: _PatchFn, preload = false): void {
696721
if (patches.hasOwnProperty(name)) {
697722
throw Error('Already loaded patch: ' + name);
698723
} else if (!global['__Zone_disable_' + name]) {
699724
const perfName = 'Zone:' + name;
700725
mark(perfName);
701-
if (_mode === 'normal') {
726+
if (_mode === 'normal' || preload) {
702727
patches[name] = fn(global, Zone, _api);
703728
} else {
704729
patches[name] = function() {
705-
fn(global, Zone, _api);
730+
return fn(global, Zone, _api);
706731
};
707732
}
708733
performanceMeasure(perfName, perfName);
709734
}
710735
}
711736

712737
static __load() {
713-
Object.keys(patches).forEach(key => patches[key]());
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+
});
714750
patchLoaded = true;
715751
}
716752

717-
static __register_patched_delegate(proto: any, property: string, origin: any) {
718-
delegates.push({proto: proto, property: property, patched: proto[property], origin: origin});
753+
static __register_patched_delegate(
754+
proto: any, property: string, origin: any, isPropertyDesc = false) {
755+
if (!isPropertyDesc) {
756+
delegates.push({
757+
proto: proto,
758+
property: property,
759+
patched: proto[property],
760+
origin: origin,
761+
isPropertyDesc: isPropertyDesc
762+
});
763+
} else {
764+
delegates.push({
765+
proto: proto,
766+
property: property,
767+
patched: Object.getOwnPropertyDescriptor(proto, property),
768+
origin: origin,
769+
isPropertyDesc: isPropertyDesc
770+
});
771+
}
719772
}
720773

721774
static __reloadAll() {
775+
if (patchLoaded) {
776+
return;
777+
}
722778
delegates.forEach(delegate => {
723-
delegate.proto[delegate.property] = delegate.patched;
779+
if (delegate.isPropertyDesc) {
780+
Object.defineProperty(delegate.proto, delegate.property, delegate.patched);
781+
} else {
782+
delegate.proto[delegate.property] = delegate.patched;
783+
}
724784
});
725785
patchLoaded = true;
726786
}
727787

728788
static __unloadAll() {
789+
if (!patchLoaded) {
790+
return;
791+
}
729792
delegates.forEach(delegate => {
730-
delegate.proto[delegate.property] = delegate.origin;
793+
if (delegate.isPropertyDesc) {
794+
Object.defineProperty(delegate.proto, delegate.property, delegate.origin);
795+
} else {
796+
delegate.proto[delegate.property] = delegate.origin;
797+
}
731798
});
732799
patchLoaded = false;
733800
}
@@ -797,8 +864,7 @@ const Zone: ZoneType = (function(global: any) {
797864
return this._zoneDelegate.invoke(this, callback, applyThis, applyArgs, source);
798865
} finally {
799866
_currentZoneFrame = _currentZoneFrame.parent!;
800-
if (_mode === 'lazy' && _currentZoneFrame.zone &&
801-
_currentZoneFrame.zone.name === '<root>') {
867+
if (_mode === 'lazy' && _currentZoneFrame.zone && !_currentZoneFrame.zone.parent) {
802868
Zone.__unloadAll();
803869
}
804870
}
@@ -822,8 +888,7 @@ const Zone: ZoneType = (function(global: any) {
822888
}
823889
} finally {
824890
_currentZoneFrame = _currentZoneFrame.parent!;
825-
if (_mode === 'lazy' && _currentZoneFrame.zone &&
826-
_currentZoneFrame.zone.name === '<root>') {
891+
if (_mode === 'lazy' && _currentZoneFrame.zone && !_currentZoneFrame.zone.parent) {
827892
Zone.__unloadAll();
828893
}
829894
}
@@ -879,8 +944,7 @@ const Zone: ZoneType = (function(global: any) {
879944
}
880945
_currentZoneFrame = _currentZoneFrame.parent!;
881946
_currentTask = previousTask;
882-
if (_mode === 'lazy' && _currentZoneFrame.zone &&
883-
_currentZoneFrame.zone.name === '<root>') {
947+
if (_mode === 'lazy' && _currentZoneFrame.zone && !_currentZoneFrame.zone.parent) {
884948
Zone.__unloadAll();
885949
}
886950
}
@@ -1330,6 +1394,8 @@ const Zone: ZoneType = (function(global: any) {
13301394
if (!nativeMicroTaskQueuePromise) {
13311395
if (global[symbolPromise]) {
13321396
nativeMicroTaskQueuePromise = global[symbolPromise].resolve(0);
1397+
} else if (_mode === 'lazy' && patchedPromise !== global['Promise']) {
1398+
nativeMicroTaskQueuePromise = global['Promise'].resolve(0);
13331399
}
13341400
}
13351401
if (nativeMicroTaskQueuePromise) {
@@ -1382,7 +1448,9 @@ const Zone: ZoneType = (function(global: any) {
13821448
eventTask: 'eventTask' = 'eventTask';
13831449

13841450
const patches: {[key: string]: any} = {};
1385-
const delegates: {proto: any, property: string, patched: any, origin: any}[] = [];
1451+
let patchedPromise: any;
1452+
const delegates:
1453+
{proto: any, property: string, patched: any, origin: any, isPropertyDesc: boolean}[] = [];
13861454
let patchLoaded = false;
13871455
const _api: _ZonePrivate = {
13881456
symbol: __symbol__,
@@ -1409,7 +1477,7 @@ const Zone: ZoneType = (function(global: any) {
14091477
let _currentZoneFrame: _ZoneFrame = {parent: null, zone: new Zone(null, null)};
14101478
let _currentTask: Task|null = null;
14111479
let _numberOfNestedTaskFrames = 0;
1412-
let _mode: 'lazy'|'normal' = 'normal';
1480+
let _mode: 'lazy'|'normal' = global['__zone_symbol__load_mode'] || 'normal';
14131481

14141482
function noop() {}
14151483

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"format": "gulp format:enforce",
2222
"karma-jasmine": "karma start karma-build-jasmine.conf.js",
2323
"karma-jasmine:es6": "karma start karma-build-jasmine.es6.conf.js",
24+
"karma-jasmine:lazy": "karma start karma-build-jasmine-lazy.conf.js",
2425
"karma-jasmine:phantomjs": "karma start karma-build-jasmine-phantomjs.conf.js --single-run",
2526
"karma-jasmine:single": "karma start karma-build-jasmine.conf.js --single-run",
2627
"karma-jasmine:autoclose": "npm run karma-jasmine:single && npm run ws-client",
@@ -40,6 +41,7 @@
4041
"tslint": "tslint -c tslint.json 'lib/**/*.ts'",
4142
"test": "npm run tsc && concurrently \"npm run tsc:w\" \"npm run ws-server\" \"npm run karma-jasmine\"",
4243
"test:es6": "npm run tsc && concurrently \"npm run tsc:w\" \"npm run ws-server\" \"npm run karma-jasmine:es6\"",
44+
"test:lazy": "npm run tsc && concurrently \"npm run tsc:w\" \"npm run karma-jasmine:lazy\"",
4345
"test:phantomjs": "npm run tsc && concurrently \"npm run tsc:w\" \"npm run ws-server\" \"npm run karma-jasmine:phantomjs\"",
4446
"test:phantomjs-single": "npm run tsc && concurrently \"npm run ws-server\" \"npm run karma-jasmine-phantomjs:autoclose\"",
4547
"test:single": "npm run tsc && concurrently \"npm run ws-server\" \"npm run karma-jasmine:autoclose\"",

test/browser-lazy-zone-setup.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
if (typeof window !== 'undefined') {
9+
(window as any)['__zone_symbol__load_mode'] = 'lazy';
10+
}

0 commit comments

Comments
 (0)