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

Commit 34c12e5

Browse files
JiaLiPassionmhevery
authored andcommitted
fix(xhr): fix#1072, should set scheduled flag to target (#1074)
1 parent a86c6d5 commit 34c12e5

3 files changed

Lines changed: 90 additions & 5 deletions

File tree

‎file-size-limit.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
{
44
"path": "dist/zone.min.js",
55
"checkTarget": true,
6-
"limit": 41500
6+
"limit": 41600
77
}
88
]
99
}

‎lib/browser/browser.ts‎

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ Zone.__load_patch('XHR', (global: any, Zone: ZoneType) => {
9696
constXHR_LISTENER=zoneSymbol('xhrListener');
9797
constXHR_SCHEDULED=zoneSymbol('xhrScheduled');
9898
constXHR_URL=zoneSymbol('xhrURL');
99+
constXHR_ERROR_BEFORE_SCHEDULED=zoneSymbol('xhrErrorBeforeScheduled');
99100

100101
interfaceXHROptionsextendsTaskData{
101102
target: any;
@@ -126,9 +127,10 @@ Zone.__load_patch('XHR', (global: any, Zone: ZoneType) => {
126127
constSCHEDULED='scheduled';
127128

128129
functionscheduleTask(task: Task){
129-
(XMLHttpRequestasany)[XHR_SCHEDULED]=false;
130130
constdata=<XHROptions>task.data;
131131
consttarget=data.target;
132+
target[XHR_SCHEDULED]=false;
133+
target[XHR_ERROR_BEFORE_SCHEDULED]=false;
132134
// remove existing event listener
133135
constlistener=target[XHR_LISTENER];
134136
if(!oriAddListener){
@@ -143,7 +145,7 @@ Zone.__load_patch('XHR', (global: any, Zone: ZoneType) => {
143145
if(target.readyState===target.DONE){
144146
// sometimes on some browsers XMLHttpRequest will fire onreadystatechange with
145147
// readyState=4 multiple times, so we need to check task state here
146-
if(!data.aborted&&(XMLHttpRequestasany)[XHR_SCHEDULED]&&task.state===SCHEDULED){
148+
if(!data.aborted&&target[XHR_SCHEDULED]&&task.state===SCHEDULED){
147149
// check whether the xhr has registered onload listener
148150
// if that is the case, the task should invoke after all
149151
// onload listeners finish.
@@ -167,6 +169,9 @@ Zone.__load_patch('XHR', (global: any, Zone: ZoneType) => {
167169
}else{
168170
task.invoke();
169171
}
172+
}elseif(!data.aborted&&target[XHR_SCHEDULED]===false){
173+
// error occurs when xhr.send()
174+
target[XHR_ERROR_BEFORE_SCHEDULED]=true;
170175
}
171176
}
172177
};
@@ -177,7 +182,7 @@ Zone.__load_patch('XHR', (global: any, Zone: ZoneType) => {
177182
target[XHR_TASK]=task;
178183
}
179184
sendNative!.apply(target,data.args);
180-
(XMLHttpRequestasany)[XHR_SCHEDULED]=true;
185+
target[XHR_SCHEDULED]=true;
181186
returntask;
182187
}
183188

@@ -215,8 +220,15 @@ Zone.__load_patch('XHR', (global: any, Zone: ZoneType) => {
215220
}else{
216221
constoptions: XHROptions=
217222
{target: self,url: self[XHR_URL],isPeriodic: false,args: args,aborted: false};
218-
returnscheduleMacroTaskWithCurrentZone(
223+
consttask=scheduleMacroTaskWithCurrentZone(
219224
XMLHTTPREQUEST_SOURCE,placeholderCallback,options,scheduleTask,clearTask);
225+
if(self&&self[XHR_ERROR_BEFORE_SCHEDULED]===true&&!options.aborted&&
226+
task.state===SCHEDULED){
227+
// xhr request throw error when send
228+
// we should invoke task instead of leaving a scheduled
229+
// pending macroTask
230+
task.invoke();
231+
}
220232
}
221233
});
222234

‎test/browser/XMLHttpRequest.spec.ts‎

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,79 @@ describe('XMLHttpRequest', function() {
266266
});
267267
});
268268

269+
it('should trigger readystatechange if xhr request trigger cors error',(done)=>{
270+
constreq=newXMLHttpRequest();
271+
leterr: any=null;
272+
try{
273+
req.open('get','file:///test',true);
274+
}catch(err){
275+
// in IE, open will throw Access is denied error
276+
done();
277+
return;
278+
}
279+
req.addEventListener('readystatechange',function(ev){
280+
if(req.readyState===4){
281+
constxhrScheduled=(reqasany)['__zone_symbol__xhrScheduled'];
282+
consttask=(reqasany)['__zone_symbol__xhrTask'];
283+
if(xhrScheduled===false){
284+
expect(task.state).toEqual('scheduling');
285+
setTimeout(()=>{
286+
if(err){
287+
expect(task.state).toEqual('unknown');
288+
}else{
289+
expect(task.state).toEqual('notScheduled');
290+
}
291+
done();
292+
});
293+
}else{
294+
expect(task.state).toEqual('scheduled');
295+
done();
296+
}
297+
}
298+
});
299+
try{
300+
req.send();
301+
}catch(error){
302+
err=error;
303+
}
304+
});
305+
306+
it('should invoke task if xhr request trigger cors error',(done)=>{
307+
constlogs: string[]=[];
308+
constzone=Zone.current.fork({
309+
name: 'xhr',
310+
onHasTask: (delegate: ZoneDelegate,curr: Zone,target: Zone,hasTask: HasTaskState)=>{
311+
logs.push(JSON.stringify(hasTask));
312+
}
313+
});
314+
constreq=newXMLHttpRequest();
315+
try{
316+
req.open('get','file:///test',true);
317+
}catch(err){
318+
// in IE, open will throw Access is denied error
319+
done();
320+
return;
321+
}
322+
zone.run(()=>{
323+
letisError=false;
324+
lettimerId=null;
325+
try{
326+
timerId=(windowasany)['__zone_symbol__setTimeout'](()=>{
327+
expect(logs).toEqual([
328+
`{"microTask":false,"macroTask":true,"eventTask":false,"change":"macroTask"}`,
329+
`{"microTask":false,"macroTask":false,"eventTask":false,"change":"macroTask"}`
330+
]);
331+
done();
332+
},500);
333+
req.send();
334+
}catch(error){
335+
isError=true;
336+
(windowasany)['__zone_symbol__clearTimeout'](timerId);
337+
done();
338+
}
339+
});
340+
});
341+
269342
it('should not throw error when get XMLHttpRequest.prototype.onreadystatechange the first time',
270343
function(){
271344
constfunc=function(){

0 commit comments

Comments
 (0)