@@ -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,33 @@ 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 ;
324
334
var ret = {
325
- response : responseData , //ie9
335
+ get response ( ) {
336
+ // object getter is part of ES5
337
+ // getter to avoid uncessary processing. only proceed if response.response is called.
338
+ // property 'response' is enumerable such that JSON.stringify(response) contains response
339
+ var responseType = xhrProxy . responseType ;
340
+ if ( ! responseType || responseType === 'text' ) {
341
+ return xhrProxy . responseText ;
342
+ }
343
+ // reference: https://shanabrian.com/web/html-css-js-technics/js-ie10-ie11-xhr-json-string.php
344
+ // reference: https://github.com/axios/axios/issues/2390
345
+ // json - W3C standard - xhrProxy.response = JSON object; responseText is unobtainable
346
+ // For details, see https://github.com/wendux/ajax-hook/issues/117
347
+ // IE 9, 10 & 11 - only responseText
348
+ if ( responseType === 'json' && typeof JSON === 'object' && ( ( navigator || 0 ) . userAgent || '' ) . indexOf ( 'Trident' ) !== - 1 ) {
349
+ return JSON . parse ( xhrProxy . responseText ) ;
350
+ }
351
+ return xhrProxy . response ;
352
+ } , //ie9
326
353
status : xhrProxy . status ,
327
354
statusText : xhrProxy . statusText ,
328
355
config : xhr . config ,
@@ -359,14 +386,21 @@ function proxyAjax(proxy, win) {
359
386
}
360
387
361
388
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 ) ;
389
+ var config = xhr ? xhr . config : null ;
390
+ if ( config && xhr && config . xhr === xhr ) {
391
+ if ( xhr . readyState === 4 && xhr . status !== 0 ) {
392
+ handleResponse ( xhr , xhrProxy ) ;
393
+ } else if ( xhr . readyState !== 4 ) {
394
+ triggerListener ( xhr , eventReadyStateChange ) ;
395
+ }
366
396
}
367
397
return true ;
368
398
}
369
399
400
+ var eventListenerFnMap = typeof WeakMap === 'function' ? function ( _this ) {
401
+ return _this . eventListenerFnMap || ( _this . eventListenerFnMap = new WeakMap ( ) ) ;
402
+ } : null ;
403
+
370
404
var _hook = ( 0 , _xhrHook . hook ) ( {
371
405
onload : preventXhrProxyCallback ,
372
406
onloadend : preventXhrProxyCallback ,
@@ -384,18 +418,33 @@ function proxyAjax(proxy, win) {
384
418
config . async = args [ 2 ] ;
385
419
config . user = args [ 3 ] ;
386
420
config . password = args [ 4 ] ;
387
- config . xhr = xhr ;
421
+ Object . defineProperty ( config , 'xhr' , {
422
+ get ( ) {
423
+ return xhr ; // xhr wil be set to null after xhr.readyState === XMLHttpRequest.DONE (4)
424
+ } ,
425
+ set ( nv ) {
426
+ if ( nv === null ) xhr = null ;
427
+ return true ;
428
+ } ,
429
+ enumerable : false ,
430
+ configurable : true
431
+ } ) ;
432
+ // config.xhr = xhr;
388
433
var evName = 'on' + eventReadyStateChange ;
389
434
if ( ! xhr [ evName ] ) {
390
435
xhr [ evName ] = function ( ) {
391
- return stateChangeCallback ( xhr , _this ) ;
436
+ return stateChangeCallback ( this , _this ) ;
392
437
} ;
393
438
}
394
439
395
440
// 如果有请求拦截器,则在调用onRequest后再打开链接。因为onRequest最佳调用时机是在send前,
396
441
// 所以我们在send拦截函数中再手动调用open,因此返回true阻止xhr.open调用。
397
442
//
398
443
// 如果没有请求拦截器,则不用阻断xhr.open调用
444
+ onRequest = onRequest_ ;
445
+ if ( onConfig ) {
446
+ if ( onConfig ( config , this ) === false ) onRequest = null ;
447
+ }
399
448
if ( onRequest ) return true ;
400
449
} ,
401
450
send : function send ( args , xhr ) {
@@ -419,18 +468,37 @@ function proxyAjax(proxy, win) {
419
468
if ( onRequest ) return true ;
420
469
} ,
421
470
addEventListener : function addEventListener ( args , xhr ) {
471
+ // args = (type:string , listener: EventListener, opt: any?)
422
472
var _this = this ;
423
473
if ( _xhrHook . events . indexOf ( args [ 0 ] ) !== - 1 ) {
424
474
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 ] ;
475
+ var Gn = function ( e ) {
476
+ var event = _xhrHook . configEvent ( e , _this ) ;
428
477
event . isTrusted = true ;
429
478
handler . call ( _this , event ) ;
430
- } ) ;
479
+ } ;
480
+ if ( eventListenerFnMap ) {
481
+ var map = eventListenerFnMap ( _this ) ;
482
+ map . set ( handler , Gn ) ;
483
+ }
484
+ getEventTarget ( xhr ) . addEventListener ( args [ 0 ] , Gn , false ) ;
431
485
return true ;
432
486
}
433
487
} ,
488
+ removeEventListener : function removeEventListener ( args , xhr ) {
489
+ // args = (type:string , listener: EventListener, opt: any?)
490
+ if ( _xhrHook . events . indexOf ( args [ 0 ] ) !== - 1 ) {
491
+ var handler = args [ 1 ] ;
492
+ if ( eventListenerFnMap ) {
493
+ var map = eventListenerFnMap ( this ) ;
494
+ var Gn = map . get ( handler ) ;
495
+ if ( Gn ) {
496
+ getEventTarget ( xhr ) . removeEventListener ( args [ 0 ] , Gn , false ) ;
497
+ return true ;
498
+ }
499
+ }
500
+ }
501
+ } ,
434
502
getAllResponseHeaders : function getAllResponseHeaders ( _ , xhr ) {
435
503
var headers = xhr . resHeader ;
436
504
if ( headers ) {
0 commit comments