@@ -217,42 +217,41 @@ export class Executor<
217217> {
218218 validatedExecutionArgs : ValidatedExecutionArgs ;
219219 finished : boolean ;
220- initialResponseAbortController : AbortController | undefined ;
221- resolverAbortControllers : Map < Path , AbortController > ;
222220 collectedErrors : CollectedErrors ;
221+ internalAbortController : AbortController ;
222+ removeExternalAbortListener : ( ( ) => void ) | undefined ;
223+ resolverAbortController : AbortController | undefined ;
224+ sharedResolverAbortSignal : AbortSignal ;
223225
224- constructor ( validatedExecutionArgs : ValidatedExecutionArgs ) {
226+ constructor (
227+ validatedExecutionArgs : ValidatedExecutionArgs ,
228+ sharedResolverAbortSignal ?: AbortSignal ,
229+ ) {
225230 this . validatedExecutionArgs = validatedExecutionArgs ;
226231 this . finished = false ;
227- this . resolverAbortControllers = new Map ( ) ;
228232 this . collectedErrors = new CollectedErrors ( ) ;
233+ this . internalAbortController = new AbortController ( ) ;
234+
235+ if ( sharedResolverAbortSignal === undefined ) {
236+ this . resolverAbortController = new AbortController ( ) ;
237+ this . sharedResolverAbortSignal = this . resolverAbortController . signal ;
238+ } else {
239+ this . sharedResolverAbortSignal = sharedResolverAbortSignal ;
240+ }
229241 }
230242
231243 executeQueryOrMutationOrSubscriptionEvent ( ) : PromiseOrValue <
232244 ExecutionResult | TAlternativeInitialResponse
233245 > {
234- const abortController = ( this . initialResponseAbortController =
235- new AbortController ( ) ) ;
236-
237- const validatedExecutionArgs = this . validatedExecutionArgs ;
238- const externalAbortSignal = validatedExecutionArgs . externalAbortSignal ;
239- let removeAbortListener : ( ( ) => void ) | undefined ;
246+ const externalAbortSignal = this . validatedExecutionArgs . externalAbortSignal ;
240247 if ( externalAbortSignal ) {
241- if ( externalAbortSignal . aborted ) {
242- throw new Error ( externalAbortSignal . reason ) ;
243- }
248+ externalAbortSignal . throwIfAborted ( ) ;
244249 const onExternalAbort = ( ) => this . cancel ( externalAbortSignal . reason ) ;
245- removeAbortListener = ( ) =>
250+ this . removeExternalAbortListener = ( ) =>
246251 externalAbortSignal . removeEventListener ( 'abort' , onExternalAbort ) ;
247252 externalAbortSignal . addEventListener ( 'abort' , onExternalAbort ) ;
248253 }
249254
250- const onFinish = ( ) => {
251- removeAbortListener ?.( ) ;
252- this . finish ( ) ;
253- abortController . signal . throwIfAborted ( ) ;
254- } ;
255-
256255 try {
257256 const {
258257 schema,
@@ -261,7 +260,7 @@ export class Executor<
261260 operation,
262261 variableValues,
263262 hideSuggestions,
264- } = validatedExecutionArgs ;
263+ } = this . validatedExecutionArgs ;
265264
266265 const { operation : operationType , selectionSet } = operation ;
267266
@@ -293,62 +292,40 @@ export class Executor<
293292 if ( isPromise ( result ) ) {
294293 const promise = result . then (
295294 ( data ) => {
296- onFinish ( ) ;
295+ this . finish ( ) ;
297296 return this . buildResponse ( data ) ;
298297 } ,
299298 ( error : unknown ) => {
300- onFinish ( ) ;
299+ this . finish ( ) ;
301300 this . collectedErrors . add ( error as GraphQLError , undefined ) ;
302301 return this . buildResponse ( null ) ;
303302 } ,
304303 ) ;
305- return externalAbortSignal
306- ? cancellablePromise ( promise , abortController . signal )
307- : promise ;
304+ return cancellablePromise ( promise , this . internalAbortController . signal ) ;
308305 }
309- onFinish ( ) ;
306+ this . finish ( ) ;
310307 return this . buildResponse ( result ) ;
311308 } catch ( error ) {
309+ this . finish ( ) ;
312310 this . collectedErrors . add ( error as GraphQLError , undefined ) ;
313- onFinish ( ) ;
314311 return this . buildResponse ( null ) ;
315312 }
316313 }
317314
318- cancel ( reason : unknown ) : void {
315+ cancel ( reason ? : unknown ) : void {
319316 if ( ! this . finished ) {
320- this . initialResponseAbortController ?. abort ( reason ) ;
321- this . finish ( reason ) ;
317+ this . finish ( ) ;
318+ this . internalAbortController . abort ( reason ) ;
319+ this . resolverAbortController ?. abort ( reason ) ;
322320 }
323321 }
324322
325- finish ( reason ?: unknown ) : void {
323+ finish ( ) : void {
326324 if ( ! this . finished ) {
327325 this . finished = true ;
328- this . triggerResolverAbortSignals ( reason ) ;
329- }
330- }
331-
332- triggerResolverAbortSignals ( reason ?: unknown ) : void {
333- const { resolverAbortControllers } = this ;
334- const finishReason =
335- reason ?? new Error ( 'Execution has already completed.' ) ;
336- for ( const abortController of resolverAbortControllers . values ( ) ) {
337- abortController . abort ( finishReason ) ;
326+ this . removeExternalAbortListener ?.( ) ;
338327 }
339- }
340-
341- getAbortSignal ( path : Path ) : AbortSignal {
342- const resolverAbortSignal = this . resolverAbortControllers . get ( path ) ?. signal ;
343- if ( resolverAbortSignal !== undefined ) {
344- return resolverAbortSignal ;
345- }
346- const abortController = new AbortController ( ) ;
347- this . resolverAbortControllers . set ( path , abortController ) ;
348- if ( this . finished ) {
349- abortController . abort ( new Error ( 'Execution has already completed.' ) ) ;
350- }
351- return abortController . signal ;
328+ this . internalAbortController . signal . throwIfAborted ( ) ;
352329 }
353330
354331 /**
@@ -358,6 +335,7 @@ export class Executor<
358335 buildResponse (
359336 data : ObjMap < unknown > | null ,
360337 ) : ExecutionResult | TAlternativeInitialResponse {
338+ this . resolverAbortController ?. abort ( ) ;
361339 const errors = this . collectedErrors . errors ;
362340 return errors . length ? { errors, data } : { data } ;
363341 }
@@ -542,7 +520,7 @@ export class Executor<
542520 toNodes ( fieldDetailsList ) ,
543521 parentType ,
544522 path ,
545- ( ) => this . getAbortSignal ( path ) ,
523+ ( ) => this . sharedResolverAbortSignal ,
546524 ) ;
547525
548526 // Get the resolve function, regardless of if its result is normal or abrupt (error).
@@ -571,7 +549,6 @@ export class Executor<
571549 path ,
572550 result ,
573551 positionContext ,
574- true ,
575552 ) ;
576553 }
577554
@@ -587,22 +564,13 @@ export class Executor<
587564 if ( isPromise ( completed ) ) {
588565 // Note: we don't rely on a `catch` method, but we do expect "thenable"
589566 // to take a second callback for the error case.
590- return completed . then (
591- ( resolved ) => {
592- this . resolverAbortControllers . delete ( path ) ;
593- return resolved ;
594- } ,
595- ( rawError : unknown ) => {
596- this . resolverAbortControllers . delete ( path ) ;
597- this . handleFieldError ( rawError , returnType , fieldDetailsList , path ) ;
598- return null ;
599- } ,
600- ) ;
567+ return completed . then ( undefined , ( rawError : unknown ) => {
568+ this . handleFieldError ( rawError , returnType , fieldDetailsList , path ) ;
569+ return null ;
570+ } ) ;
601571 }
602- this . resolverAbortControllers . delete ( path ) ;
603572 return completed ;
604573 } catch ( rawError ) {
605- this . resolverAbortControllers . delete ( path ) ;
606574 this . handleFieldError ( rawError , returnType , fieldDetailsList , path ) ;
607575 return null ;
608576 }
@@ -755,7 +723,6 @@ export class Executor<
755723 path : Path ,
756724 result : Promise < unknown > ,
757725 positionContext : TPositionContext | undefined ,
758- isFieldValue ?: boolean ,
759726 ) : Promise < unknown > {
760727 try {
761728 const resolved = await result ;
@@ -774,14 +741,8 @@ export class Executor<
774741 if ( isPromise ( completed ) ) {
775742 completed = await completed ;
776743 }
777- if ( isFieldValue ) {
778- this . resolverAbortControllers . delete ( path ) ;
779- }
780744 return completed ;
781745 } catch ( rawError ) {
782- if ( isFieldValue ) {
783- this . resolverAbortControllers . delete ( path ) ;
784- }
785746 this . handleFieldError ( rawError , returnType , fieldDetailsList , path ) ;
786747 return null ;
787748 }
0 commit comments