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

Commit e933cbd

Browse files
authored
feat: make codebase more modular so that only parts of it can be loaded (#748)
1 parent 89132fd commit e933cbd

13 files changed

Lines changed: 959 additions & 879 deletions

File tree

karma-build.conf.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,7 @@ module.exports = function (config) {
1111
config.files.push('build/test/wtf_mock.js');
1212
config.files.push('build/test/custom_error.js');
1313
config.files.push('build/lib/zone.js');
14+
config.files.push('build/lib/common/promise.js');
15+
config.files.push('build/lib/common/error-rewrite.js');
1416
config.files.push('build/test/main.js');
1517
};

lib/browser/browser.ts

Lines changed: 167 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -15,168 +15,184 @@ import {eventTargetPatch} from './event-target';
1515
import {propertyDescriptorPatch} from './property-descriptor';
1616
import {registerElementPatch} from './register-element';
1717

18-
const set = 'set';
19-
const clear = 'clear';
20-
const blockingMethods = ['alert', 'prompt', 'confirm'];
21-
const _global: any =
22-
typeof window !== 'undefined' && window || typeof self !== 'undefined' && self || global;
23-
24-
patchTimer(_global, set, clear, 'Timeout');
25-
patchTimer(_global, set, clear, 'Interval');
26-
patchTimer(_global, set, clear, 'Immediate');
27-
patchTimer(_global, 'request', 'cancel', 'AnimationFrame');
28-
patchTimer(_global, 'mozRequest', 'mozCancel', 'AnimationFrame');
29-
patchTimer(_global, 'webkitRequest', 'webkitCancel', 'AnimationFrame');
30-
31-
for (let i = 0; i < blockingMethods.length; i++) {
32-
const name = blockingMethods[i];
33-
patchMethod(_global, name, (delegate, symbol, name) => {
34-
return function(s: any, args: any[]) {
35-
return Zone.current.run(delegate, _global, args, name);
36-
};
37-
});
38-
}
39-
40-
eventTargetPatch(_global);
41-
// patch XMLHttpRequestEventTarget's addEventListener/removeEventListener
42-
const XMLHttpRequestEventTarget = (_global as any)['XMLHttpRequestEventTarget'];
43-
if (XMLHttpRequestEventTarget && XMLHttpRequestEventTarget.prototype) {
44-
patchEventTargetMethods(XMLHttpRequestEventTarget.prototype);
45-
}
46-
propertyDescriptorPatch(_global);
47-
patchClass('MutationObserver');
48-
patchClass('WebKitMutationObserver');
49-
patchClass('FileReader');
50-
propertyPatch();
51-
registerElementPatch(_global);
52-
53-
// Treat XMLHTTPRequest as a macrotask.
54-
patchXHR(_global);
55-
56-
const XHR_TASK = zoneSymbol('xhrTask');
57-
const XHR_SYNC = zoneSymbol('xhrSync');
58-
const XHR_LISTENER = zoneSymbol('xhrListener');
59-
const XHR_SCHEDULED = zoneSymbol('xhrScheduled');
60-
61-
interface XHROptions extends TaskData {
62-
target: any;
63-
args: any[];
64-
aborted: boolean;
65-
}
66-
67-
function patchXHR(window: any) {
68-
function findPendingTask(target: any) {
69-
const pendingTask: Task = target[XHR_TASK];
70-
return pendingTask;
18+
Zone.__load_patch('timers', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
19+
const set = 'set';
20+
const clear = 'clear';
21+
patchTimer(global, set, clear, 'Timeout');
22+
patchTimer(global, set, clear, 'Interval');
23+
patchTimer(global, set, clear, 'Immediate');
24+
patchTimer(global, 'request', 'cancel', 'AnimationFrame');
25+
patchTimer(global, 'mozRequest', 'mozCancel', 'AnimationFrame');
26+
patchTimer(global, 'webkitRequest', 'webkitCancel', 'AnimationFrame');
27+
});
28+
29+
Zone.__load_patch('blocking', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
30+
const blockingMethods = ['alert', 'prompt', 'confirm'];
31+
for (let i = 0; i < blockingMethods.length; i++) {
32+
const name = blockingMethods[i];
33+
patchMethod(global, name, (delegate, symbol, name) => {
34+
return function(s: any, args: any[]) {
35+
return Zone.current.run(delegate, global, args, name);
36+
};
37+
});
38+
}
39+
});
40+
41+
Zone.__load_patch('EventTarget', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
42+
eventTargetPatch(global);
43+
// patch XMLHttpRequestEventTarget's addEventListener/removeEventListener
44+
const XMLHttpRequestEventTarget = (global as any)['XMLHttpRequestEventTarget'];
45+
if (XMLHttpRequestEventTarget && XMLHttpRequestEventTarget.prototype) {
46+
patchEventTargetMethods(XMLHttpRequestEventTarget.prototype);
47+
}
48+
patchClass('MutationObserver');
49+
patchClass('WebKitMutationObserver');
50+
patchClass('FileReader');
51+
});
52+
53+
Zone.__load_patch('on_property', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
54+
propertyDescriptorPatch(global);
55+
propertyPatch();
56+
registerElementPatch(global);
57+
});
58+
59+
Zone.__load_patch('XHR', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
60+
// Treat XMLHTTPRequest as a macrotask.
61+
patchXHR(global);
62+
63+
const XHR_TASK = zoneSymbol('xhrTask');
64+
const XHR_SYNC = zoneSymbol('xhrSync');
65+
const XHR_LISTENER = zoneSymbol('xhrListener');
66+
const XHR_SCHEDULED = zoneSymbol('xhrScheduled');
67+
68+
interface XHROptions extends TaskData {
69+
target: any;
70+
args: any[];
71+
aborted: boolean;
7172
}
7273

73-
function scheduleTask(task: Task) {
74-
(XMLHttpRequest as any)[XHR_SCHEDULED] = false;
75-
const data = <XHROptions>task.data;
76-
// remove existing event listener
77-
const listener = data.target[XHR_LISTENER];
78-
if (listener) {
79-
data.target.removeEventListener('readystatechange', listener);
74+
function patchXHR(window: any) {
75+
function findPendingTask(target: any) {
76+
const pendingTask: Task = target[XHR_TASK];
77+
return pendingTask;
8078
}
81-
const newListener = data.target[XHR_LISTENER] = () => {
82-
if (data.target.readyState === data.target.DONE) {
83-
// sometimes on some browsers XMLHttpRequest will fire onreadystatechange with
84-
// readyState=4 multiple times, so we need to check task state here
85-
if (!data.aborted && (XMLHttpRequest as any)[XHR_SCHEDULED] && task.state === 'scheduled') {
86-
task.invoke();
87-
}
79+
80+
function scheduleTask(task: Task) {
81+
(XMLHttpRequest as any)[XHR_SCHEDULED] = false;
82+
const data = <XHROptions>task.data;
83+
// remove existing event listener
84+
const listener = data.target[XHR_LISTENER];
85+
if (listener) {
86+
data.target.removeEventListener('readystatechange', listener);
8887
}
89-
};
90-
data.target.addEventListener('readystatechange', newListener);
88+
const newListener = data.target[XHR_LISTENER] = () => {
89+
if (data.target.readyState === data.target.DONE) {
90+
// sometimes on some browsers XMLHttpRequest will fire onreadystatechange with
91+
// readyState=4 multiple times, so we need to check task state here
92+
if (!data.aborted && (XMLHttpRequest as any)[XHR_SCHEDULED] &&
93+
task.state === 'scheduled') {
94+
task.invoke();
95+
}
96+
}
97+
};
98+
data.target.addEventListener('readystatechange', newListener);
9199

92-
const storedTask: Task = data.target[XHR_TASK];
93-
if (!storedTask) {
94-
data.target[XHR_TASK] = task;
100+
const storedTask: Task = data.target[XHR_TASK];
101+
if (!storedTask) {
102+
data.target[XHR_TASK] = task;
103+
}
104+
sendNative.apply(data.target, data.args);
105+
(XMLHttpRequest as any)[XHR_SCHEDULED] = true;
106+
return task;
95107
}
96-
sendNative.apply(data.target, data.args);
97-
(XMLHttpRequest as any)[XHR_SCHEDULED] = true;
98-
return task;
99-
}
100108

101-
function placeholderCallback() {}
109+
function placeholderCallback() {}
102110

103-
function clearTask(task: Task) {
104-
const data = <XHROptions>task.data;
105-
// Note - ideally, we would call data.target.removeEventListener here, but it's too late
106-
// to prevent it from firing. So instead, we store info for the event listener.
107-
data.aborted = true;
108-
return abortNative.apply(data.target, data.args);
109-
}
110-
111-
const openNative: Function =
112-
patchMethod(window.XMLHttpRequest.prototype, 'open', () => function(self: any, args: any[]) {
113-
self[XHR_SYNC] = args[2] == false;
114-
return openNative.apply(self, args);
115-
});
116-
117-
const sendNative: Function =
118-
patchMethod(window.XMLHttpRequest.prototype, 'send', () => function(self: any, args: any[]) {
119-
const zone = Zone.current;
120-
if (self[XHR_SYNC]) {
121-
// if the XHR is sync there is no task to schedule, just execute the code.
122-
return sendNative.apply(self, args);
123-
} else {
124-
const options: XHROptions =
125-
{target: self, isPeriodic: false, delay: null, args: args, aborted: false};
126-
return zone.scheduleMacroTask(
127-
'XMLHttpRequest.send', placeholderCallback, options, scheduleTask, clearTask);
128-
}
129-
});
111+
function clearTask(task: Task) {
112+
const data = <XHROptions>task.data;
113+
// Note - ideally, we would call data.target.removeEventListener here, but it's too late
114+
// to prevent it from firing. So instead, we store info for the event listener.
115+
data.aborted = true;
116+
return abortNative.apply(data.target, data.args);
117+
}
130118

131-
const abortNative = patchMethod(
132-
window.XMLHttpRequest.prototype, 'abort',
133-
(delegate: Function) => function(self: any, args: any[]) {
134-
const task: Task = findPendingTask(self);
135-
if (task && typeof task.type == 'string') {
136-
// If the XHR has already completed, do nothing.
137-
// If the XHR has already been aborted, do nothing.
138-
// Fix #569, call abort multiple times before done will cause
139-
// macroTask task count be negative number
140-
if (task.cancelFn == null || (task.data && (<XHROptions>task.data).aborted)) {
141-
return;
119+
const openNative: Function = patchMethod(
120+
window.XMLHttpRequest.prototype, 'open', () => function(self: any, args: any[]) {
121+
self[XHR_SYNC] = args[2] == false;
122+
return openNative.apply(self, args);
123+
});
124+
125+
const sendNative: Function = patchMethod(
126+
window.XMLHttpRequest.prototype, 'send', () => function(self: any, args: any[]) {
127+
const zone = Zone.current;
128+
if (self[XHR_SYNC]) {
129+
// if the XHR is sync there is no task to schedule, just execute the code.
130+
return sendNative.apply(self, args);
131+
} else {
132+
const options: XHROptions =
133+
{target: self, isPeriodic: false, delay: null, args: args, aborted: false};
134+
return zone.scheduleMacroTask(
135+
'XMLHttpRequest.send', placeholderCallback, options, scheduleTask, clearTask);
142136
}
143-
task.zone.cancelTask(task);
137+
});
138+
139+
const abortNative = patchMethod(
140+
window.XMLHttpRequest.prototype, 'abort',
141+
(delegate: Function) => function(self: any, args: any[]) {
142+
const task: Task = findPendingTask(self);
143+
if (task && typeof task.type == 'string') {
144+
// If the XHR has already completed, do nothing.
145+
// If the XHR has already been aborted, do nothing.
146+
// Fix #569, call abort multiple times before done will cause
147+
// macroTask task count be negative number
148+
if (task.cancelFn == null || (task.data && (<XHROptions>task.data).aborted)) {
149+
return;
150+
}
151+
task.zone.cancelTask(task);
152+
}
153+
// Otherwise, we are trying to abort an XHR which has not yet been sent, so there is no
154+
// task
155+
// to cancel. Do nothing.
156+
});
157+
}
158+
});
159+
160+
Zone.__load_patch('geo', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
161+
/// GEO_LOCATION
162+
if (global['navigator'] && global['navigator'].geolocation) {
163+
patchPrototype(global['navigator'].geolocation, ['getCurrentPosition', 'watchPosition']);
164+
}
165+
});
166+
167+
Zone.__load_patch('toString', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
168+
// patch Func.prototype.toString to let them look like native
169+
patchFuncToString();
170+
// patch Object.prototype.toString to let them look like native
171+
patchObjectToString();
172+
});
173+
174+
Zone.__load_patch('promiseRejectionHandler', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
175+
// handle unhandled promise rejection
176+
function findPromiseRejectionHandler(evtName: string) {
177+
return function(e: any) {
178+
const eventTasks = findEventTask(global, evtName);
179+
eventTasks.forEach(eventTask => {
180+
// windows has added unhandledrejection event listener
181+
// trigger the event listener
182+
const PromiseRejectionEvent = global['PromiseRejectionEvent'];
183+
if (PromiseRejectionEvent) {
184+
const evt = new PromiseRejectionEvent(evtName, {promise: e.promise, reason: e.rejection});
185+
eventTask.invoke(evt);
144186
}
145-
// Otherwise, we are trying to abort an XHR which has not yet been sent, so there is no task
146-
// to cancel. Do nothing.
147187
});
148-
}
149-
150-
/// GEO_LOCATION
151-
if (_global['navigator'] && _global['navigator'].geolocation) {
152-
patchPrototype(_global['navigator'].geolocation, ['getCurrentPosition', 'watchPosition']);
153-
}
154-
155-
// patch Func.prototype.toString to let them look like native
156-
patchFuncToString();
157-
// patch Object.prototype.toString to let them look like native
158-
patchObjectToString();
159-
160-
// handle unhandled promise rejection
161-
function findPromiseRejectionHandler(evtName: string) {
162-
return function(e: any) {
163-
const eventTasks = findEventTask(_global, evtName);
164-
eventTasks.forEach(eventTask => {
165-
// windows has added unhandledrejection event listener
166-
// trigger the event listener
167-
const PromiseRejectionEvent = _global['PromiseRejectionEvent'];
168-
if (PromiseRejectionEvent) {
169-
const evt = new PromiseRejectionEvent(evtName, {promise: e.promise, reason: e.rejection});
170-
eventTask.invoke(evt);
171-
}
172-
});
173-
};
174-
}
188+
};
189+
}
175190

176-
if (_global['PromiseRejectionEvent']) {
177-
(Zone as any)[zoneSymbol('unhandledPromiseRejectionHandler')] =
178-
findPromiseRejectionHandler('unhandledrejection');
191+
if (global['PromiseRejectionEvent']) {
192+
(Zone as any)[zoneSymbol('unhandledPromiseRejectionHandler')] =
193+
findPromiseRejectionHandler('unhandledrejection');
179194

180-
(Zone as any)[zoneSymbol('rejectionHandledHandler')] =
181-
findPromiseRejectionHandler('rejectionhandled');
182-
}
195+
(Zone as any)[zoneSymbol('rejectionHandledHandler')] =
196+
findPromiseRejectionHandler('rejectionhandled');
197+
}
198+
});

lib/browser/rollup-main.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@
88

99

1010
import '../zone';
11-
import './browser';
11+
import '../common/promise';
12+
import '../common/error-rewrite';
13+
import './browser';

lib/browser/websocket.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,6 @@ export function apply(_global: any) {
3939
return proxySocket;
4040
};
4141
for (const prop in WS) {
42-
_global.WebSocket[prop] = WS[prop];
42+
_global['WebSocket'][prop] = WS[prop];
4343
}
4444
}

0 commit comments

Comments
 (0)