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

Commit 066a247

Browse files
committed
WIP(core): can unload, reload patch modules
1 parent 1ba8519 commit 066a247

File tree

5 files changed

+213
-50
lines changed

5 files changed

+213
-50
lines changed

lib/browser/browser.ts

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
import {findEventTasks} from '../common/events';
1414
import {patchTimer} from '../common/timers';
15-
import {bindArguments, patchClass, patchMacroTask, patchMethod, patchOnProperties, patchPrototype, scheduleMacroTaskWithCurrentZone, ZONE_SYMBOL_ADD_EVENT_LISTENER, ZONE_SYMBOL_REMOVE_EVENT_LISTENER, zoneSymbol} from '../common/utils';
15+
import {bindArguments, generateUnPatchAndRePatch, patchClass, patchMacroTask, patchMethod, patchOnProperties, patchPrototype, scheduleMacroTaskWithCurrentZone, ZONE_SYMBOL_ADD_EVENT_LISTENER, ZONE_SYMBOL_REMOVE_EVENT_LISTENER, zoneSymbol} from '../common/utils';
1616

1717
import {propertyPatch} from './define-property';
1818
import {eventTargetPatch, patchEvent} from './event-target';
@@ -23,23 +23,30 @@ Zone.__load_patch('util', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
2323
api.patchOnProperties = patchOnProperties;
2424
api.patchMethod = patchMethod;
2525
api.bindArguments = bindArguments;
26+
api.generateUnPatchAndRePatch = generateUnPatchAndRePatch;
27+
return undefined;
2628
});
2729

28-
Zone.__load_patch('timers', (global: any) => {
29-
const set = 'set';
30-
const clear = 'clear';
31-
patchTimer(global, set, clear, 'Timeout');
32-
patchTimer(global, set, clear, 'Interval');
33-
patchTimer(global, set, clear, 'Immediate');
30+
Zone.__load_patch('timers', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
31+
const timerMethods = ['Timeout', 'Interval', 'Immediate'];
32+
timerMethods.forEach(m => patchTimer(global, 'set', 'clear', m));
33+
const timerMethodsWithPrefix =
34+
timerMethods.map(m => 'set' + m).concat(timerMethods.map(m => 'clear' + m));
35+
return api.generateUnPatchAndRePatch([{target: global, methods: timerMethodsWithPrefix}]);
3436
});
3537

36-
Zone.__load_patch('requestAnimationFrame', (global: any) => {
38+
Zone.__load_patch('requestAnimationFrame', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
39+
const methodsToPatch = [
40+
'requestAnimationFrame', 'cancelAnimationFrame', 'mozRequestAnimationFrame',
41+
'mozCancelAnimationFrame', 'webkitRequestAnimationFrame', 'webkitCancelAnimationFrame'
42+
];
3743
patchTimer(global, 'request', 'cancel', 'AnimationFrame');
3844
patchTimer(global, 'mozRequest', 'mozCancel', 'AnimationFrame');
3945
patchTimer(global, 'webkitRequest', 'webkitCancel', 'AnimationFrame');
46+
return api.generateUnPatchAndRePatch([{target: global, methods: methodsToPatch}]);
4047
});
4148

42-
Zone.__load_patch('blocking', (global: any, Zone: ZoneType) => {
49+
Zone.__load_patch('blocking', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
4350
const blockingMethods = ['alert', 'prompt', 'confirm'];
4451
for (let i = 0; i < blockingMethods.length; i++) {
4552
const name = blockingMethods[i];
@@ -49,6 +56,7 @@ Zone.__load_patch('blocking', (global: any, Zone: ZoneType) => {
4956
};
5057
});
5158
}
59+
return api.generateUnPatchAndRePatch([{target: global, methods: blockingMethods}]);
5260
});
5361

5462
Zone.__load_patch('EventTarget', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
@@ -59,15 +67,31 @@ Zone.__load_patch('EventTarget', (global: any, Zone: ZoneType, api: _ZonePrivate
5967
}
6068

6169
patchEvent(global, api);
62-
eventTargetPatch(global, api);
70+
const apiTypes: any[] = eventTargetPatch(global, api);
6371
// patch XMLHttpRequestEventTarget's addEventListener/removeEventListener
6472
const XMLHttpRequestEventTarget = (global as any)['XMLHttpRequestEventTarget'];
6573
if (XMLHttpRequestEventTarget && XMLHttpRequestEventTarget.prototype) {
6674
api.patchEventTarget(global, [XMLHttpRequestEventTarget.prototype]);
6775
}
76+
const methods = ['addEventListener', 'removeEventListener'];
77+
return api.generateUnPatchAndRePatch(
78+
apiTypes.filter(apiType => !!apiType)
79+
.map(apiType => {
80+
return {target: apiType, methods: methods};
81+
})
82+
.concat(
83+
typeof Event !== 'undefined' ?
84+
[{target: Event.prototype, methods: ['stopImmediatePropagation']}] :
85+
[]));
86+
});
87+
88+
Zone.__load_patch('Observer', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
6889
patchClass('MutationObserver');
6990
patchClass('WebKitMutationObserver');
7091
patchClass('IntersectionObserver');
92+
});
93+
94+
Zone.__load_patch('FileReader', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
7195
patchClass('FileReader');
7296
});
7397

lib/browser/event-target.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ export function eventTargetPatch(_global: any, api: _ZonePrivate) {
106106
patchEventTarget(_global, apiTypes, {vh: checkIEAndCrossContext});
107107
api.patchEventTarget = patchEventTarget;
108108

109-
return true;
109+
return apiTypes;
110110
}
111111

112112
export function patchEvent(global: any, api: _ZonePrivate) {

lib/common/promise.ts

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr
9595
const REJECTED_NO_CATCH = 0;
9696

9797
function makeResolver(promise: ZoneAwarePromise<any>, state: boolean): (value: any) => void {
98-
return (v) => {
98+
return v => {
9999
try {
100100
resolvePromise(promise, state, v);
101101
} catch (err) {
@@ -164,7 +164,7 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr
164164
(promise as any)[symbolValue] = value;
165165

166166
if ((promise as any)[symbolFinally] === symbolFinally) {
167-
// the promise is generated by Promise.prototype.finally
167+
// the promise is generated by Promise.prototype.finally
168168
if (state === RESOLVED) {
169169
// the state is resolved, should ignore the value
170170
// and use parent promise value
@@ -243,19 +243,24 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr
243243
clearRejectedNoCatch(promise);
244244
const promiseState = (promise as any)[symbolState];
245245
const delegate = promiseState ?
246-
(typeof onFulfilled === 'function') ? onFulfilled : forwardResolution :
247-
(typeof onRejected === 'function') ? onRejected : forwardRejection;
246+
typeof onFulfilled === 'function' ? onFulfilled : forwardResolution :
247+
typeof onRejected === 'function' ? onRejected : forwardRejection;
248248
zone.scheduleMicroTask(source, () => {
249249
try {
250250
const parentPromiseValue = (promise as any)[symbolValue];
251-
const isFinallyPromise = chainPromise && symbolFinally === (chainPromise as any)[symbolFinally];
251+
const isFinallyPromise =
252+
chainPromise && symbolFinally === (chainPromise as any)[symbolFinally];
252253
if (isFinallyPromise) {
253254
// if the promise is generated from finally call, keep parent promise's state and value
254255
(chainPromise as any)[symbolParentPromiseValue] = parentPromiseValue;
255256
(chainPromise as any)[symbolParentPromiseState] = promiseState;
256257
}
257258
// should not pass value to finally callback
258-
const value = zone.run(delegate, undefined, isFinallyPromise && delegate !== forwardRejection && delegate !== forwardResolution ? [] : [parentPromiseValue]);
259+
const value = zone.run(
260+
delegate, undefined,
261+
isFinallyPromise && delegate !== forwardRejection && delegate !== forwardResolution ?
262+
[] :
263+
[parentPromiseValue]);
259264
resolvePromise(chainPromise, true, value);
260265
} catch (error) {
261266
// if error occurs, should always return this error
@@ -316,7 +321,7 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr
316321
value = this.resolve(value);
317322
}
318323
value.then(
319-
((index) => (value: any) => {
324+
(index => (value: any) => {
320325
resolvedValues[index] = value;
321326
count--;
322327
if (!count) {
@@ -386,7 +391,7 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr
386391
ZoneAwarePromise['race'] = ZoneAwarePromise.race;
387392
ZoneAwarePromise['all'] = ZoneAwarePromise.all;
388393

389-
const NativePromise = global[symbolPromise] = global['Promise'];
394+
const NativePromise = (global[symbolPromise] = global['Promise']);
390395
const ZONE_AWARE_PROMISE = Zone.__symbol__('ZoneAwarePromise');
391396

392397
let desc = ObjectGetOwnPropertyDescriptor(global, 'Promise');
@@ -449,6 +454,7 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr
449454
});
450455
return wrapped.then(onResolve, onReject);
451456
};
457+
Ctor.prototype['__zone_symbol__patchedThen'] = Ctor.prototype.then;
452458
(Ctor as any)[symbolThenPatched] = true;
453459
}
454460

@@ -477,5 +483,14 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr
477483

478484
// This is not part of public API, but it is useful for tests, so we expose it.
479485
(Promise as any)[Zone.__symbol__('uncaughtPromiseErrors')] = _uncaughtPromiseErrors;
480-
return ZoneAwarePromise;
486+
return {
487+
unPatchFn: function() {
488+
global['__zone_symbol__ZoneAwarePromise'] = NativePromise;
489+
NativePromise.prototype.then = NativePromise.prototype[symbolThen];
490+
},
491+
rePatchFn: function() {
492+
global['__zone_symbol__ZoneAwarePromise'] = ZoneAwarePromise;
493+
NativePromise.prototype.then = NativePromise.prototype['__zone_symbol__patchedThen'];
494+
}
495+
};
481496
});

lib/common/utils.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,3 +452,29 @@ export function isIEOrEdge() {
452452
} catch (error) {
453453
}
454454
}
455+
456+
export function generateUnPatchAndRePatch(patches: [{target: any, methods: string[]}]) {
457+
return {
458+
unPatchFn: () => {
459+
patches.forEach(patch => {
460+
patch.methods.forEach(m => {
461+
const originalDelegate = patch.target[zoneSymbol(m)];
462+
if (originalDelegate) {
463+
patch.target[m] = originalDelegate;
464+
}
465+
});
466+
});
467+
},
468+
rePatchFn: () => {
469+
patches.forEach(patch => {
470+
patch.methods.forEach(m => {
471+
const method = patch.target[m];
472+
const originalDelegate = method && method[zoneSymbol(m)];
473+
if (originalDelegate) {
474+
patch.target[m] = originalDelegate;
475+
}
476+
});
477+
});
478+
}
479+
};
480+
};

0 commit comments

Comments
 (0)