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

Commit 4529684

Browse files
committed
fix(xhr): should invoke xhr task after onload is triggered
1 parent c8c5990 commit 4529684

File tree

2 files changed

+42
-9
lines changed

2 files changed

+42
-9
lines changed

Diff for: lib/browser/browser.ts

+23-1
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,29 @@ Zone.__load_patch('XHR', (global: any, Zone: ZoneType) => {
144144
// sometimes on some browsers XMLHttpRequest will fire onreadystatechange with
145145
// readyState=4 multiple times, so we need to check task state here
146146
if (!data.aborted && (XMLHttpRequest as any)[XHR_SCHEDULED] && task.state === SCHEDULED) {
147-
task.invoke();
147+
// check whether the xhr has registered onload listener
148+
// if that is the case, the task should invoke after all
149+
// onload listeners finish.
150+
const loadTasks = target['__zone_symbol__loadfalse'];
151+
if (loadTasks && loadTasks.length > 0) {
152+
const oriInvoke = task.invoke;
153+
task.invoke = function() {
154+
// need to load the tasks again, because in other
155+
// load listener, they may remove themselves
156+
const loadTasks = target['__zone_symbol__loadfalse'];
157+
for (let i = 0; i < loadTasks.length; i++) {
158+
if (loadTasks[i] === task) {
159+
loadTasks.splice(i, 1);
160+
}
161+
}
162+
if (!data.aborted && task.state === SCHEDULED) {
163+
oriInvoke.call(task);
164+
}
165+
};
166+
loadTasks.push(task);
167+
} else {
168+
task.invoke();
169+
}
148170
}
149171
}
150172
};

Diff for: test/browser/XMLHttpRequest.spec.ts

+19-8
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,34 @@ describe('XMLHttpRequest', function() {
1717

1818
it('should intercept XHRs and treat them as MacroTasks', function(done) {
1919
let req: XMLHttpRequest;
20-
const testZoneWithWtf =
21-
Zone.current.fork((Zone as any)['wtfZoneSpec']).fork({name: 'TestZone'});
20+
let onStable: any;
21+
const testZoneWithWtf = Zone.current.fork((Zone as any)['wtfZoneSpec']).fork({
22+
name: 'TestZone',
23+
onHasTask: (delegate: ZoneDelegate, curr: Zone, target: Zone, hasTask: HasTaskState) => {
24+
if (!hasTask.macroTask) {
25+
onStable && onStable();
26+
}
27+
}
28+
});
2229

2330
testZoneWithWtf.run(() => {
2431
req = new XMLHttpRequest();
32+
const logs: string[] = [];
2533
req.onload = () => {
26-
// The last entry in the log should be the invocation for the current onload,
27-
// which will vary depending on browser environment. The prior entries
28-
// should be the invocation of the send macrotask.
29-
expect(wtfMock.log[wtfMock.log.length - 3])
30-
.toEqual('> Zone:invokeTask:XMLHttpRequest.send("<root>::ProxyZone::WTF::TestZone")');
34+
logs.push('onload');
35+
};
36+
onStable = function() {
3137
expect(wtfMock.log[wtfMock.log.length - 2])
38+
.toEqual('> Zone:invokeTask:XMLHttpRequest.send("<root>::ProxyZone::WTF::TestZone")');
39+
expect(wtfMock.log[wtfMock.log.length - 1])
3240
.toEqual('< Zone:invokeTask:XMLHttpRequest.send');
3341
if (supportPatchXHROnProperty()) {
34-
expect(wtfMock.log[wtfMock.log.length - 1])
42+
expect(wtfMock.log[wtfMock.log.length - 3])
43+
.toMatch(/\< Zone\:invokeTask.*addEventListener\:load/);
44+
expect(wtfMock.log[wtfMock.log.length - 4])
3545
.toMatch(/\> Zone\:invokeTask.*addEventListener\:load/);
3646
}
47+
expect(logs).toEqual(['onload']);
3748
done();
3849
};
3950

0 commit comments

Comments
 (0)