@@ -239,7 +239,7 @@ function trim(str) {
239
239
}
240
240
241
241
function getEventTarget ( xhr ) {
242
- return xhr . watcher || ( xhr . watcher = document . createElement ( 'a' ) ) ;
242
+ return xhr . watcher || ( xhr . watcher = typeof document . createDocumentFragment === 'function' ? document . createDocumentFragment ( ) : document . createElement ( 'a' ) ) ;
243
243
}
244
244
245
245
function triggerListener ( xhr , name ) {
@@ -275,11 +275,21 @@ Handler[prototype] = Object.create({
275
275
triggerListener ( xhr , eventReadyStateChange ) ;
276
276
triggerListener ( xhr , eventLoad ) ;
277
277
triggerListener ( xhr , eventLoadEnd ) ;
278
+ if ( xhr . readyState === 4 ) {
279
+ if ( xhr . config ) xhr . config . xhr = null ;
280
+ xhr [ 'on' + eventReadyStateChange ] = null ;
281
+ xhr . config = null ;
282
+ }
278
283
} ,
279
284
reject : function reject ( error ) {
280
285
this . xhrProxy . status = 0 ;
281
286
triggerListener ( this . xhr , error . type ) ;
282
287
triggerListener ( this . xhr , eventLoadEnd ) ;
288
+ if ( xhr . readyState === 4 ) {
289
+ if ( xhr . config ) xhr . config . xhr = null ;
290
+ xhr [ 'on' + eventReadyStateChange ] = null ;
291
+ xhr . config = null ;
292
+ }
283
293
}
284
294
} ) ;
285
295
@@ -313,16 +323,46 @@ var ErrorHandler = makeHandler(function (error) {
313
323
} ) ;
314
324
315
325
function proxyAjax ( proxy , win ) {
316
- var onRequest = proxy . onRequest ,
317
- onResponse = proxy . onResponse ,
318
- onError = proxy . onError ;
326
+ var onConfig = proxy . onConfig ,
327
+ onRequest = null ,
328
+ onRequest_ = proxy . onRequest ,
329
+ onResponse = proxy . onResponse ,
330
+ onError = proxy . onError ;
319
331
320
332
function handleResponse ( xhr , xhrProxy ) {
321
333
var handler = new ResponseHandler ( xhr ) ;
322
- var responseType = xhrProxy . responseType ;
323
- var responseData = ! responseType || responseType === 'text' || responseType === 'json' ? xhrProxy . responseText : xhrProxy . response ;
334
+ var getResponseData = function ( ) {
335
+ // object getter is part of ES5
336
+ // getter to avoid uncessary processing. only proceed if response.response is called.
337
+ // property 'response' is enumerable such that JSON.stringify(response) contains response
338
+ var responseType = xhrProxy . responseType ;
339
+ if ( ! responseType || responseType === 'text' ) {
340
+ return xhrProxy . responseText ;
341
+ }
342
+ // reference: https://shanabrian.com/web/html-css-js-technics/js-ie10-ie11-xhr-json-string.php
343
+ // reference: https://github.com/axios/axios/issues/2390
344
+ // json - W3C standard - xhrProxy.response = JSON object; responseText is unobtainable
345
+ // For details, see https://github.com/wendux/ajax-hook/issues/117
346
+ // IE 9, 10 & 11 - only responseText
347
+ if ( responseType === 'json' && typeof JSON === 'object' && ( ( navigator || 0 ) . userAgent || '' ) . indexOf ( 'Trident' ) !== - 1 ) {
348
+ return JSON . parse ( xhrProxy . responseText ) ;
349
+ }
350
+ return xhrProxy . response ;
351
+ } ; //ie9
352
+ var responseData ;
324
353
var ret = {
325
- response : responseData , //ie9
354
+ get response ( ) {
355
+ if ( getResponseData ) {
356
+ responseData = getResponseData ( ) ;
357
+ getResponseData = null ;
358
+ }
359
+ return responseData ;
360
+ } ,
361
+ set response ( nv ) {
362
+ getResponseData = null ;
363
+ responseData = nv ;
364
+ return true ;
365
+ } ,
326
366
status : xhrProxy . status ,
327
367
statusText : xhrProxy . statusText ,
328
368
config : xhr . config ,
@@ -359,14 +399,21 @@ function proxyAjax(proxy, win) {
359
399
}
360
400
361
401
function stateChangeCallback ( xhr , xhrProxy ) {
362
- if ( xhr . readyState === 4 && xhr . status !== 0 ) {
363
- handleResponse ( xhr , xhrProxy ) ;
364
- } else if ( xhr . readyState !== 4 ) {
365
- triggerListener ( xhr , eventReadyStateChange ) ;
402
+ var config = xhr ? xhr . config : null ;
403
+ if ( config && xhr && config . xhr === xhr ) {
404
+ if ( xhr . readyState === 4 && xhr . status !== 0 ) {
405
+ handleResponse ( xhr , xhrProxy ) ;
406
+ } else if ( xhr . readyState !== 4 ) {
407
+ triggerListener ( xhr , eventReadyStateChange ) ;
408
+ }
366
409
}
367
410
return true ;
368
411
}
369
412
413
+ var eventListenerFnMap = typeof WeakMap === 'function' ? function ( _this ) {
414
+ return _this . eventListenerFnMap || ( _this . eventListenerFnMap = new WeakMap ( ) ) ;
415
+ } : null ;
416
+
370
417
var _hook = ( 0 , _xhrHook . hook ) ( {
371
418
onload : preventXhrProxyCallback ,
372
419
onloadend : preventXhrProxyCallback ,
@@ -384,18 +431,33 @@ function proxyAjax(proxy, win) {
384
431
config . async = args [ 2 ] ;
385
432
config . user = args [ 3 ] ;
386
433
config . password = args [ 4 ] ;
387
- config . xhr = xhr ;
434
+ Object . defineProperty ( config , 'xhr' , {
435
+ get ( ) {
436
+ return xhr ; // xhr wil be set to null after xhr.readyState === XMLHttpRequest.DONE (4)
437
+ } ,
438
+ set ( nv ) {
439
+ if ( nv === null ) xhr = null ;
440
+ return true ;
441
+ } ,
442
+ enumerable : false ,
443
+ configurable : true
444
+ } ) ;
445
+ // config.xhr = xhr;
388
446
var evName = 'on' + eventReadyStateChange ;
389
447
if ( ! xhr [ evName ] ) {
390
448
xhr [ evName ] = function ( ) {
391
- return stateChangeCallback ( xhr , _this ) ;
449
+ return stateChangeCallback ( this , _this ) ;
392
450
} ;
393
451
}
394
452
395
453
// 如果有请求拦截器,则在调用onRequest后再打开链接。因为onRequest最佳调用时机是在send前,
396
454
// 所以我们在send拦截函数中再手动调用open,因此返回true阻止xhr.open调用。
397
455
//
398
456
// 如果没有请求拦截器,则不用阻断xhr.open调用
457
+ onRequest = onRequest_ ;
458
+ if ( onConfig ) {
459
+ if ( onConfig ( config , this ) === false ) onRequest = null ;
460
+ }
399
461
if ( onRequest ) return true ;
400
462
} ,
401
463
send : function send ( args , xhr ) {
@@ -419,18 +481,37 @@ function proxyAjax(proxy, win) {
419
481
if ( onRequest ) return true ;
420
482
} ,
421
483
addEventListener : function addEventListener ( args , xhr ) {
484
+ // args = (type:string , listener: EventListener, opt: any?)
422
485
var _this = this ;
423
486
if ( _xhrHook . events . indexOf ( args [ 0 ] ) !== - 1 ) {
424
487
var handler = args [ 1 ] ;
425
- getEventTarget ( xhr ) . addEventListener ( args [ 0 ] , function ( e ) {
426
- var event = ( 0 , _xhrHook . configEvent ) ( e , _this ) ;
427
- event . type = args [ 0 ] ;
488
+ var Gn = function ( e ) {
489
+ var event = _xhrHook . configEvent ( e , _this ) ;
428
490
event . isTrusted = true ;
429
491
handler . call ( _this , event ) ;
430
- } ) ;
492
+ } ;
493
+ if ( eventListenerFnMap ) {
494
+ var map = eventListenerFnMap ( _this ) ;
495
+ map . set ( handler , Gn ) ;
496
+ }
497
+ getEventTarget ( xhr ) . addEventListener ( args [ 0 ] , Gn , false ) ;
431
498
return true ;
432
499
}
433
500
} ,
501
+ removeEventListener : function removeEventListener ( args , xhr ) {
502
+ // args = (type:string , listener: EventListener, opt: any?)
503
+ if ( _xhrHook . events . indexOf ( args [ 0 ] ) !== - 1 ) {
504
+ var handler = args [ 1 ] ;
505
+ if ( eventListenerFnMap ) {
506
+ var map = eventListenerFnMap ( this ) ;
507
+ var Gn = map . get ( handler ) ;
508
+ if ( Gn ) {
509
+ getEventTarget ( xhr ) . removeEventListener ( args [ 0 ] , Gn , false ) ;
510
+ return true ;
511
+ }
512
+ }
513
+ }
514
+ } ,
434
515
getAllResponseHeaders : function getAllResponseHeaders ( _ , xhr ) {
435
516
var headers = xhr . resHeader ;
436
517
if ( headers ) {
0 commit comments