@@ -32,6 +32,7 @@ import type {
3232 GraphQLObjectType ,
3333 GraphQLOutputType ,
3434 GraphQLResolveInfo ,
35+ GraphQLResolveInfoHelpers ,
3536 GraphQLTypeResolver ,
3637} from '../type/definition.js' ;
3738import {
@@ -231,6 +232,10 @@ export class Executor<
231232 abortResultPromise : ( ( reason ?: unknown ) => void ) | undefined ;
232233 resolverAbortController : AbortController | undefined ;
233234 getAbortSignal : ( ) => AbortSignal | undefined ;
235+ getAsyncHelpers : ( ) => GraphQLResolveInfoHelpers ;
236+ promiseAll : < T > (
237+ values : ReadonlyArray < PromiseOrValue < T > > ,
238+ ) => Promise < Array < T > > ;
234239
235240 constructor (
236241 validatedExecutionArgs : ValidatedExecutionArgs ,
@@ -249,8 +254,11 @@ export class Executor<
249254 } else {
250255 this . sharedExecutionContext = sharedExecutionContext ;
251256 }
252- const { getAbortSignal } = this . sharedExecutionContext ;
257+ const { getAbortSignal, getAsyncHelpers, promiseAll } =
258+ this . sharedExecutionContext ;
253259 this . getAbortSignal = getAbortSignal ;
260+ this . getAsyncHelpers = getAsyncHelpers ;
261+ this . promiseAll = promiseAll ;
254262 }
255263
256264 executeQueryOrMutationOrSubscriptionEvent ( ) : PromiseOrValue <
@@ -261,10 +269,7 @@ export class Executor<
261269 if ( externalAbortSignal ) {
262270 externalAbortSignal . throwIfAborted ( ) ;
263271 const onExternalAbort = ( ) => {
264- const aborted = this . abort ( externalAbortSignal . reason ) ;
265- if ( isPromise ( aborted ) ) {
266- aborted . catch ( ( ) => undefined ) ;
267- }
272+ this . abort ( externalAbortSignal . reason ) ;
268273 } ;
269274 removeExternalAbortListener = ( ) =>
270275 externalAbortSignal . removeEventListener ( 'abort' , onExternalAbort ) ;
@@ -324,6 +329,7 @@ export class Executor<
324329 return this . buildResponse ( null ) ;
325330 } ,
326331 ) ;
332+ this . sharedExecutionContext . asyncWorkTracker . add ( promise ) ;
327333 const { promise : cancellablePromise , abort : abortResultPromise } =
328334 withCancellation ( promise ) ;
329335 this . abortResultPromise = abortResultPromise ;
@@ -347,7 +353,7 @@ export class Executor<
347353 }
348354 }
349355
350- abort ( reason ?: unknown ) : PromiseOrValue < void > {
356+ abort ( reason ?: unknown ) : void {
351357 if ( this . aborted ) {
352358 return ;
353359 }
@@ -506,8 +512,9 @@ export class Executor<
506512 }
507513 } catch ( error ) {
508514 if ( containsPromise ) {
509- // Ensure that any promises returned by other fields are handled, as they may also reject.
510- promiseForObject ( results ) . catch ( ( ) => undefined ) ;
515+ this . sharedExecutionContext . asyncWorkTracker . addValues (
516+ Object . values ( results ) ,
517+ ) ;
511518 }
512519 throw error ;
513520 }
@@ -520,7 +527,7 @@ export class Executor<
520527 // Otherwise, results is a map from field name to the result of resolving that
521528 // field, which is possibly a promise. Return a promise that will return this
522529 // same map, but with any promises replaced with the values they resolved to.
523- return promiseForObject ( results ) ;
530+ return promiseForObject ( results , this . promiseAll ) ;
524531 }
525532
526533 /**
@@ -557,6 +564,7 @@ export class Executor<
557564 parentType ,
558565 path ,
559566 this . getAbortSignal ,
567+ this . getAsyncHelpers ,
560568 ) ;
561569
562570 // Get the resolve function, regardless of if its result is normal or abrupt (error).
@@ -853,24 +861,30 @@ export class Executor<
853861 index ++ ;
854862 }
855863 } catch ( error ) {
856- // eslint-disable-next-line @typescript-eslint/no-floating-promises
857- returnIteratorCatchingErrors ( asyncIterator ) ;
864+ this . sharedExecutionContext . asyncWorkTracker . add (
865+ returnIteratorCatchingErrors ( asyncIterator ) ,
866+ ) ;
858867 if ( containsPromise ) {
859- Promise . all ( completedResults ) . catch ( ( ) => undefined ) ;
868+ this . sharedExecutionContext . asyncWorkTracker . addValues (
869+ completedResults ,
870+ ) ;
860871 }
861872 throw error ;
862873 }
863874
864875 // Throwing on completion outside of the loop may allow engines to better optimize
865876 if ( this . aborted ) {
866877 if ( ! iteration ?. done ) {
867- // eslint-disable-next-line @typescript-eslint/no-floating-promises
868- returnIteratorCatchingErrors ( asyncIterator ) ;
878+ this . sharedExecutionContext . asyncWorkTracker . add (
879+ returnIteratorCatchingErrors ( asyncIterator ) ,
880+ ) ;
869881 }
870882 throw new Error ( 'Aborted!' ) ;
871883 }
872884
873- return containsPromise ? Promise . all ( completedResults ) : completedResults ;
885+ return containsPromise
886+ ? this . promiseAll ( completedResults )
887+ : completedResults ;
874888 }
875889
876890 /* c8 ignore next 12 */
@@ -991,15 +1005,17 @@ export class Executor<
9911005 index ++ ;
9921006 }
9931007 } catch ( error ) {
994- const maybePromises = containsPromise ? completedResults : [ ] ;
995- maybePromises . push ( ...collectIteratorPromises ( iterator ) ) ;
996- if ( maybePromises . length ) {
997- Promise . all ( maybePromises ) . catch ( ( ) => undefined ) ;
1008+ const asyncWorkTracker = this . sharedExecutionContext . asyncWorkTracker ;
1009+ if ( containsPromise ) {
1010+ asyncWorkTracker . addValues ( completedResults ) ;
9981011 }
1012+ asyncWorkTracker . addValues ( collectIteratorPromises ( iterator ) ) ;
9991013 throw error ;
10001014 }
10011015
1002- return containsPromise ? Promise . all ( completedResults ) : completedResults ;
1016+ return containsPromise
1017+ ? this . promiseAll ( completedResults )
1018+ : completedResults ;
10031019 }
10041020
10051021 completeMaybePromisedListItemValue (
0 commit comments