@@ -56,6 +56,21 @@ export type GMXHRResponseType = {
5656 error ?: string ;
5757} ;
5858
59+ type TXhrCallBackArg = {
60+ //
61+ finalUrl : string ;
62+ readyState : ReadyStateCode ;
63+ status : number ;
64+ statusText : string ;
65+ responseHeaders : string ;
66+ error ?: string ;
67+ //
68+ useFetch : boolean ;
69+ eventType : string ;
70+ ok : boolean ;
71+ contentType : string ;
72+ } ;
73+
5974export type GMXHRResponseTypeWithError = GMXHRResponseType & Required < Pick < GMXHRResponseType , "error" > > ;
6075
6176export const toBlobURL = ( a : GMApi , blob : Blob ) : Promise < string > | string => {
@@ -209,7 +224,7 @@ export function GM_xmlhttpRequest(
209224 }
210225 let connect : MessageConnect | null ;
211226 const responseTypeOriginal = details . responseType ?. toLocaleLowerCase ( ) || "" ;
212- let doAbort : any = null ;
227+ let doAbort : ( ( o : TXhrCallBackArg ) => void ) | null = null ;
213228 ( async ( ) => {
214229 const [ urlResolved , dataResolved ] = await Promise . all ( [ urlPromiseLike , dataPromise ] ) ;
215230 const u = new URL ( urlResolved , window . location . href ) ;
@@ -285,6 +300,7 @@ export function GM_xmlhttpRequest(
285300 }
286301
287302 let refCleanup : ( ( ) => void ) | null = ( ) => {
303+ // 执行此操作会使连结断开。因此 fetch error, timeout 等出现后不能立即执行,应留待 onloadend 后呼叫
288304 // 清掉函数参考,避免各变数参考无法GC
289305 makeXHRCallbackParam = null ;
290306 onMessageHandler = null ;
@@ -419,22 +435,7 @@ export function GM_xmlhttpRequest(
419435 return retParamObject ;
420436 } ;
421437
422- const makeXHRCallbackParam_ = (
423- res : {
424- //
425- finalUrl : string ;
426- readyState : ReadyStateCode ;
427- status : number ;
428- statusText : string ;
429- responseHeaders : string ;
430- error ?: string ;
431- //
432- useFetch : boolean ;
433- eventType : string ;
434- ok : boolean ;
435- contentType : string ;
436- } & Record < string , any >
437- ) => {
438+ const makeXHRCallbackParam_ = ( res : TXhrCallBackArg ) => {
438439 if ( ( res . readyState === 4 || reqDone ) && res . eventType !== "progress" ) allowResponse = true ;
439440 let resError : Record < string , any > | null = null ;
440441 if (
@@ -502,12 +503,33 @@ export function GM_xmlhttpRequest(
502503 return makeResponseRet ( retParam , addGetters , res . contentType ) ;
503504 } ;
504505 let makeXHRCallbackParam : typeof makeXHRCallbackParam_ | null = makeXHRCallbackParam_ ;
505- doAbort = ( data : any ) => {
506+ let loadendCalled = false ;
507+ const doLoadEnd = ( data : TXhrCallBackArg ) => {
508+ if ( ! loadendCalled ) {
509+ loadendCalled = true ;
510+ reqDone = true ;
511+ responseText = false ;
512+ finalResultBuffers = null ;
513+ finalResultText = null ;
514+ const xhrResponse = makeXHRCallbackParam ?.( data ) ?? { } ;
515+ details . onloadend ?.( xhrResponse ) ;
516+ if ( errorOccur === null ) {
517+ retPromiseResolve ?.( xhrResponse ) ;
518+ } else {
519+ retPromiseReject ?.( errorOccur ) ;
520+ }
521+ refCleanup ?.( ) ;
522+ }
523+ } ;
524+ doAbort = ( data : TXhrCallBackArg ) => {
506525 if ( ! reqDone ) {
507526 errorOccur = "AbortError" ;
508527 details . onabort ?.( makeXHRCallbackParam ?.( data ) ?? { } ) ;
509528 reqDone = true ;
510- refCleanup ?.( ) ;
529+ // 不要进行 refCleanup !要等待最后的 onloadend
530+ // refCleanup?.();
531+ // doAbort 不是由通讯管控 onloadend. 需要手动处理. 排程在下一个 microTask 避免影响 Abort 流程
532+ Promise . resolve ( { ...data , type : "loadend" } ) . then ( doLoadEnd ) ;
511533 }
512534 doAbort = null ;
513535 } ;
@@ -543,8 +565,17 @@ export function GM_xmlhttpRequest(
543565 error : message ,
544566 } ) ;
545567 reqDone = true ;
546- retPromiseReject ?.( message ) ;
547- refCleanup ?.( ) ;
568+ // 不要进行 refCleanup !要等待最后的 onloadend
569+ // refCleanup?.();
570+
571+ // 此错误多为 API 非正常执行,估计不会有 loadend 触发。见 Aborted 处理
572+ Promise . resolve ( {
573+ error : "loadend" ,
574+ responseHeaders : "" ,
575+ readyState : 0 ,
576+ status : 0 ,
577+ statusText : "" ,
578+ } as TXhrCallBackArg ) . then ( doLoadEnd ) ;
548579 }
549580 return ;
550581 }
@@ -621,18 +652,7 @@ export function GM_xmlhttpRequest(
621652 details . onload ?.( makeXHRCallbackParam ?.( data ) ?? { } ) ;
622653 break ;
623654 case "onloadend" : {
624- reqDone = true ;
625- responseText = false ;
626- finalResultBuffers = null ;
627- finalResultText = null ;
628- const xhrResponse = makeXHRCallbackParam ?.( data ) ?? { } ;
629- details . onloadend ?.( xhrResponse ) ;
630- if ( errorOccur === null ) {
631- retPromiseResolve ?.( xhrResponse ) ;
632- } else {
633- retPromiseReject ?.( errorOccur ) ;
634- }
635- refCleanup ?.( ) ;
655+ doLoadEnd ( data ) ;
636656 break ;
637657 }
638658 case "onloadstart" :
@@ -669,7 +689,8 @@ export function GM_xmlhttpRequest(
669689 errorOccur = "TimeoutError" ;
670690 details . ontimeout ?.( makeXHRCallbackParam ?.( data ) ?? { } ) ;
671691 reqDone = true ;
672- refCleanup ?.( ) ;
692+ // 不要进行 refCleanup !要等待最后的 onloadend
693+ // refCleanup?.();
673694 }
674695 break ;
675696 case "onerror" :
@@ -678,7 +699,8 @@ export function GM_xmlhttpRequest(
678699 errorOccur = data . error ;
679700 details . onerror ?.( ( makeXHRCallbackParam ?.( data ) ?? { } ) as GMXHRResponseTypeWithError ) ;
680701 reqDone = true ;
681- refCleanup ?.( ) ;
702+ // 不要进行 refCleanup !要等待最后的 onloadend
703+ // refCleanup?.();
682704 }
683705 break ;
684706 case "onabort" :
@@ -715,7 +737,7 @@ export function GM_xmlhttpRequest(
715737 readyState : 0 ,
716738 status : 0 ,
717739 statusText : "" ,
718- } ) as GMXHRResponseType ;
740+ } as TXhrCallBackArg ) ;
719741 reqDone = true ;
720742 }
721743 } ,
0 commit comments