Skip to content

Commit 908e1ee

Browse files
committed
ref(perf): cache publish decision in excutor
1 parent deacc24 commit 908e1ee

2 files changed

Lines changed: 21 additions & 7 deletions

File tree

src/diagnostics.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ export function enableDiagnosticsChannel(dc: MinimalDiagnosticsChannel): void {
139139
*
140140
* @internal
141141
*/
142-
function shouldTrace(
142+
export function shouldTrace(
143143
channel: MinimalTracingChannel | undefined,
144144
): channel is MinimalTracingChannel {
145145
// eslint-disable-next-line @typescript-eslint/no-unnecessary-boolean-literal-compare

src/execution/Executor.ts

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ import {
4444
} from '../type/definition.js';
4545
import type { GraphQLSchema } from '../type/schema.js';
4646

47-
import { maybeTraceMixed } from '../diagnostics.js';
47+
import type { MinimalTracingChannel } from '../diagnostics.js';
48+
import { getChannels, maybeTraceMixed, shouldTrace } from '../diagnostics.js';
4849

4950
import { withCancellation } from './cancellablePromise.js';
5051
import type {
@@ -244,6 +245,12 @@ export class Executor<
244245
values: ReadonlyArray<PromiseOrValue<T>>,
245246
) => Promise<Array<T>>;
246247

248+
// Resolved once per Executor so the per-field gate in `executeField` is a
249+
// single member read + null check, not a `getChannels()?.resolve` walk +
250+
// `hasSubscribers` read on every resolution. Undefined when diagnostics
251+
// are off or nobody is listening at construction time.
252+
_resolveChannel: MinimalTracingChannel | undefined;
253+
247254
constructor(
248255
validatedExecutionArgs: ValidatedExecutionArgs,
249256
sharedExecutionContext?: SharedExecutionContext,
@@ -253,6 +260,11 @@ export class Executor<
253260
this.abortReason = defaultAbortReason;
254261
this.collectedErrors = new CollectedErrors();
255262

263+
const resolveChannel = getChannels()?.resolve;
264+
this._resolveChannel = shouldTrace(resolveChannel)
265+
? resolveChannel
266+
: undefined;
267+
256268
if (sharedExecutionContext === undefined) {
257269
this.resolverAbortController = new AbortController();
258270
this.sharedExecutionContext = createSharedExecutionContext(
@@ -610,11 +622,13 @@ export class Executor<
610622
// The resolve function's optional third argument is a context value that
611623
// is provided to every resolve function within an execution. It is commonly
612624
// used to represent an authenticated user, or request-specific caches.
613-
const result = maybeTraceMixed(
614-
'resolve',
615-
() => buildResolveCtx(info, args, fieldDef.resolve === undefined),
616-
() => resolveFn(source, args, contextValue, info),
617-
);
625+
const result = this._resolveChannel
626+
? maybeTraceMixed(
627+
'resolve',
628+
() => buildResolveCtx(info, args, fieldDef.resolve === undefined),
629+
() => resolveFn(source, args, contextValue, info),
630+
)
631+
: resolveFn(source, args, contextValue, info);
618632

619633
if (isPromise(result)) {
620634
return this.completePromisedValue(

0 commit comments

Comments
 (0)