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

Commit 6e2f13c

Browse files
hmdhkmhevery
authored andcommitted
fix(XHR): Don't send sync XHR through ZONE
fixes #377
1 parent dcaeddb commit 6e2f13c

2 files changed

Lines changed: 40 additions & 13 deletions

File tree

lib/browser/browser.ts

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ registerElementPatch(_global);
3939
patchXHR(_global);
4040

4141
const XHR_TASK = zoneSymbol('xhrTask');
42+
const XHR_SYNC = zoneSymbol('xhrSync');
4243

4344
interface XHROptions extends TaskData {
4445
target: any;
@@ -65,7 +66,7 @@ function patchXHR(window: any) {
6566
if (!storedTask) {
6667
data.target[XHR_TASK] = task;
6768
}
68-
setNative.apply(data.target, data.args);
69+
sendNative.apply(data.target, data.args);
6970
return task;
7071
}
7172

@@ -77,23 +78,32 @@ function patchXHR(window: any) {
7778
// Note - ideally, we would call data.target.removeEventListener here, but it's too late
7879
// to prevent it from firing. So instead, we store info for the event listener.
7980
data.aborted = true;
80-
return clearNative.apply(data.target, data.args);
81+
return abortNative.apply(data.target, data.args);
8182
}
8283

83-
var setNative = patchMethod(window.XMLHttpRequest.prototype, 'send', () => function(self: any, args: any[]) {
84-
var zone = Zone.current;
84+
var openNative = patchMethod(window.XMLHttpRequest.prototype, 'open', () => function(self: any, args: any[]) {
85+
self[XHR_SYNC] = args[2] == false;
86+
return openNative.apply(self, args);
87+
};
8588

86-
var options: XHROptions = {
87-
target: self,
88-
isPeriodic: false,
89-
delay: null,
90-
args: args,
91-
aborted: false
92-
};
93-
return zone.scheduleMacroTask('XMLHttpRequest.send', placeholderCallback, options, scheduleTask, clearTask);
89+
var sendNative = patchMethod(window.XMLHttpRequest.prototype, 'send', () => function(self: any, args: any[]) {
90+
var zone = Zone.current;
91+
if (self[XHR_SYNC]) {
92+
// if the XHR is sync there is no task to schedule, just execute the code.
93+
return sendNative.apply(self, args);
94+
} else {
95+
var options: XHROptions = {
96+
target: self,
97+
isPeriodic: false,
98+
delay: null,
99+
args: args,
100+
aborted: false
101+
};
102+
return zone.scheduleMacroTask('XMLHttpRequest.send', placeholderCallback, options, scheduleTask, clearTask);
103+
}
94104
});
95105

96-
var clearNative = patchMethod(window.XMLHttpRequest.prototype, 'abort', (delegate: Function) => function(self: any, args: any[]) {
106+
var abortNative = patchMethod(window.XMLHttpRequest.prototype, 'abort', (delegate: Function) => function(self: any, args: any[]) {
97107
var task: Task = findPendingTask(self);
98108
if (task && typeof task.type == 'string') {
99109
// If the XHR has already completed, do nothing.

test/browser/XMLHttpRequest.spec.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,23 @@ describe('XMLHttpRequest', function () {
147147
}
148148
});
149149

150+
it('should work with synchronous XMLHttpRequest', function () {
151+
const log = [];
152+
Zone.current.fork({
153+
name: 'sync-xhr-test',
154+
onHasTask: function(delegate: ZoneDelegate, current: Zone, target: Zone,
155+
hasTaskState: HasTaskState) {
156+
log.push(hasTaskState);
157+
delegate.hasTask(target, hasTaskState);
158+
}
159+
}).run(() => {
160+
var req = new XMLHttpRequest();
161+
req.open('get', '/', false);
162+
req.send();
163+
});
164+
expect(log).toEqual([]);
165+
});
166+
150167
it('should preserve static constants', function() {
151168
expect(XMLHttpRequest.UNSENT).toEqual(0);
152169
expect(XMLHttpRequest.OPENED).toEqual(1);

0 commit comments

Comments
 (0)