@@ -239,7 +239,7 @@ function trim(str) {
239239}
240240
241241function 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' ) ) ;
243243}
244244
245245function triggerListener ( xhr , name ) {
@@ -275,11 +275,21 @@ Handler[prototype] = Object.create({
275275 triggerListener ( xhr , eventReadyStateChange ) ;
276276 triggerListener ( xhr , eventLoad ) ;
277277 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+ }
278283 } ,
279284 reject : function reject ( error ) {
280285 this . xhrProxy . status = 0 ;
281286 triggerListener ( this . xhr , error . type ) ;
282287 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+ }
283293 }
284294} ) ;
285295
@@ -313,16 +323,46 @@ var ErrorHandler = makeHandler(function (error) {
313323} ) ;
314324
315325function 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 ;
319331
320332 function handleResponse ( xhr , xhrProxy ) {
321333 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 ;
324353 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+ } ,
326366 status : xhrProxy . status ,
327367 statusText : xhrProxy . statusText ,
328368 config : xhr . config ,
@@ -359,14 +399,21 @@ function proxyAjax(proxy, win) {
359399 }
360400
361401 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+ }
366409 }
367410 return true ;
368411 }
369412
413+ var eventListenerFnMap = typeof WeakMap === 'function' ? function ( _this ) {
414+ return _this . eventListenerFnMap || ( _this . eventListenerFnMap = new WeakMap ( ) ) ;
415+ } : null ;
416+
370417 var _hook = ( 0 , _xhrHook . hook ) ( {
371418 onload : preventXhrProxyCallback ,
372419 onloadend : preventXhrProxyCallback ,
@@ -384,18 +431,33 @@ function proxyAjax(proxy, win) {
384431 config . async = args [ 2 ] ;
385432 config . user = args [ 3 ] ;
386433 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;
388446 var evName = 'on' + eventReadyStateChange ;
389447 if ( ! xhr [ evName ] ) {
390448 xhr [ evName ] = function ( ) {
391- return stateChangeCallback ( xhr , _this ) ;
449+ return stateChangeCallback ( this , _this ) ;
392450 } ;
393451 }
394452
395453 // 如果有请求拦截器,则在调用onRequest后再打开链接。因为onRequest最佳调用时机是在send前,
396454 // 所以我们在send拦截函数中再手动调用open,因此返回true阻止xhr.open调用。
397455 //
398456 // 如果没有请求拦截器,则不用阻断xhr.open调用
457+ onRequest = onRequest_ ;
458+ if ( onConfig ) {
459+ if ( onConfig ( config , this ) === false ) onRequest = null ;
460+ }
399461 if ( onRequest ) return true ;
400462 } ,
401463 send : function send ( args , xhr ) {
@@ -419,18 +481,37 @@ function proxyAjax(proxy, win) {
419481 if ( onRequest ) return true ;
420482 } ,
421483 addEventListener : function addEventListener ( args , xhr ) {
484+ // args = (type:string , listener: EventListener, opt: any?)
422485 var _this = this ;
423486 if ( _xhrHook . events . indexOf ( args [ 0 ] ) !== - 1 ) {
424487 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 ) ;
428490 event . isTrusted = true ;
429491 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 ) ;
431498 return true ;
432499 }
433500 } ,
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+ } ,
434515 getAllResponseHeaders : function getAllResponseHeaders ( _ , xhr ) {
435516 var headers = xhr . resHeader ;
436517 if ( headers ) {
0 commit comments