Skip to content

Commit 9e6c0e2

Browse files
authored
perf: do not use undefined for empty error array (#4469)
Revert previously attempted micro-optimization as it no longer produces (never produced?) a true performance benefit.
1 parent ec58004 commit 9e6c0e2

File tree

3 files changed

+26
-39
lines changed

3 files changed

+26
-39
lines changed

src/execution/IncrementalPublisher.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import {
3232
export function buildIncrementalResponse(
3333
context: IncrementalPublisherContext,
3434
result: ObjMap<unknown>,
35-
errors: ReadonlyArray<GraphQLError> | undefined,
35+
errors: ReadonlyArray<GraphQLError>,
3636
newDeferredFragmentRecords: ReadonlyArray<DeferredFragmentRecord> | undefined,
3737
incrementalDataRecords: ReadonlyArray<IncrementalDataRecord>,
3838
): ExperimentalIncrementalExecutionResults {
@@ -75,7 +75,7 @@ class IncrementalPublisher {
7575

7676
buildResponse(
7777
data: ObjMap<unknown>,
78-
errors: ReadonlyArray<GraphQLError> | undefined,
78+
errors: ReadonlyArray<GraphQLError>,
7979
newDeferredFragmentRecords:
8080
| ReadonlyArray<DeferredFragmentRecord>
8181
| undefined,
@@ -88,10 +88,9 @@ class IncrementalPublisher {
8888

8989
const pending = this._toPendingResults(newRootNodes);
9090

91-
const initialResult: InitialIncrementalExecutionResult =
92-
errors === undefined
93-
? { data, pending, hasNext: true }
94-
: { errors, data, pending, hasNext: true };
91+
const initialResult: InitialIncrementalExecutionResult = errors.length
92+
? { errors, data, pending, hasNext: true }
93+
: { data, pending, hasNext: true };
9594

9695
return {
9796
initialResult,

src/execution/execute.ts

Lines changed: 20 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -168,15 +168,15 @@ export interface ValidatedExecutionArgs {
168168

169169
export interface ExecutionContext {
170170
validatedExecutionArgs: ValidatedExecutionArgs;
171-
errors: Array<GraphQLError> | undefined;
171+
errors: Array<GraphQLError>;
172172
abortSignalListener: AbortSignalListener | undefined;
173173
completed: boolean;
174174
cancellableStreams: Set<CancellableStreamRecord> | undefined;
175175
errorPropagation: boolean;
176176
}
177177

178178
interface IncrementalContext {
179-
errors: Array<GraphQLError> | undefined;
179+
errors: Array<GraphQLError>;
180180
completed: boolean;
181181
deferUsageSet?: DeferUsageSet | undefined;
182182
}
@@ -338,7 +338,7 @@ export function experimentalExecuteQueryOrMutationOrSubscriptionEvent(
338338
const abortSignal = validatedExecutionArgs.abortSignal;
339339
const exeContext: ExecutionContext = {
340340
validatedExecutionArgs,
341-
errors: undefined,
341+
errors: [],
342342
abortSignalListener: abortSignal
343343
? new AbortSignalListener(abortSignal)
344344
: undefined,
@@ -395,7 +395,7 @@ export function experimentalExecuteQueryOrMutationOrSubscriptionEvent(
395395
exeContext.abortSignalListener?.disconnect();
396396
return {
397397
data: null,
398-
errors: withError(exeContext.errors, error as GraphQLError),
398+
errors: [...exeContext.errors, error as GraphQLError],
399399
};
400400
},
401401
);
@@ -407,17 +407,10 @@ export function experimentalExecuteQueryOrMutationOrSubscriptionEvent(
407407
// TODO: add test case for synchronous null bubbling to root with cancellation
408408
/* c8 ignore next */
409409
exeContext.abortSignalListener?.disconnect();
410-
return { data: null, errors: withError(exeContext.errors, error) };
410+
return { data: null, errors: [...exeContext.errors, error] };
411411
}
412412
}
413413

414-
function withError(
415-
errors: Array<GraphQLError> | undefined,
416-
error: GraphQLError,
417-
): ReadonlyArray<GraphQLError> {
418-
return errors === undefined ? [error] : [...errors, error];
419-
}
420-
421414
function buildDataResponse(
422415
exeContext: ExecutionContext,
423416
graphqlWrappedResult: GraphQLWrappedResult<ObjMap<unknown>>,
@@ -430,7 +423,7 @@ function buildDataResponse(
430423
const errors = exeContext.errors;
431424
if (incrementalDataRecords === undefined) {
432425
exeContext.abortSignalListener?.disconnect();
433-
return errors !== undefined ? { errors, data } : { data };
426+
return errors.length ? { errors, data } : { data };
434427
}
435428

436429
return buildIncrementalResponse(
@@ -1076,12 +1069,7 @@ function handleFieldError(
10761069
// Otherwise, error protection is applied, logging the error and resolving
10771070
// a null value for this field if one is encountered.
10781071
const context = incrementalContext ?? exeContext;
1079-
let errors = context.errors;
1080-
if (errors === undefined) {
1081-
errors = [];
1082-
context.errors = errors;
1083-
}
1084-
errors.push(error);
1072+
context.errors.push(error);
10851073
}
10861074

10871075
/**
@@ -2513,7 +2501,7 @@ function collectExecutionGroups(
25132501
path,
25142502
groupedFieldSet,
25152503
{
2516-
errors: undefined,
2504+
errors: [],
25172505
completed: false,
25182506
deferUsageSet,
25192507
},
@@ -2578,7 +2566,7 @@ function executeExecutionGroup(
25782566
return {
25792567
pendingExecutionGroup,
25802568
path: pathToArray(path),
2581-
errors: withError(incrementalContext.errors, error),
2569+
errors: [...incrementalContext.errors, error],
25822570
};
25832571
}
25842572

@@ -2598,7 +2586,7 @@ function executeExecutionGroup(
25982586
return {
25992587
pendingExecutionGroup,
26002588
path: pathToArray(path),
2601-
errors: withError(incrementalContext.errors, error as GraphQLError),
2589+
errors: [...incrementalContext.errors, error as GraphQLError],
26022590
};
26032591
},
26042592
);
@@ -2614,7 +2602,7 @@ function executeExecutionGroup(
26142602
}
26152603

26162604
function buildCompletedExecutionGroup(
2617-
errors: ReadonlyArray<GraphQLError> | undefined,
2605+
errors: ReadonlyArray<GraphQLError>,
26182606
pendingExecutionGroup: PendingExecutionGroup,
26192607
path: Path | undefined,
26202608
result: GraphQLWrappedResult<ObjMap<unknown>>,
@@ -2627,7 +2615,7 @@ function buildCompletedExecutionGroup(
26272615
return {
26282616
pendingExecutionGroup,
26292617
path: pathToArray(path),
2630-
result: errors === undefined ? { data } : { data, errors },
2618+
result: errors.length ? { errors, data } : { data },
26312619
newDeferredFragmentRecords,
26322620
incrementalDataRecords,
26332621
};
@@ -2664,7 +2652,7 @@ function buildSyncStreamItemQueue(
26642652
initialPath,
26652653
initialItem,
26662654
exeContext,
2667-
{ errors: undefined, completed: false },
2655+
{ errors: [], completed: false },
26682656
fieldDetailsList,
26692657
info,
26702658
itemType,
@@ -2681,7 +2669,7 @@ function buildSyncStreamItemQueue(
26812669
/* c8 ignore next 6 */
26822670
if (currentStreamItem instanceof BoxedPromiseOrValue) {
26832671
const result = currentStreamItem.value;
2684-
if (!isPromise(result) && result.errors !== undefined) {
2672+
if (!isPromise(result) && result.item === undefined) {
26852673
break;
26862674
}
26872675
}
@@ -2695,7 +2683,7 @@ function buildSyncStreamItemQueue(
26952683
itemPath,
26962684
value,
26972685
exeContext,
2698-
{ errors: undefined, completed: false },
2686+
{ errors: [], completed: false },
26992687
fieldDetailsList,
27002688
info,
27012689
itemType,
@@ -2787,7 +2775,7 @@ async function getNextAsyncStreamItemResult(
27872775
itemPath,
27882776
iteration.value,
27892777
exeContext,
2790-
{ errors: undefined, completed: false },
2778+
{ errors: [], completed: false },
27912779
fieldDetailsList,
27922780
info,
27932781
itemType,
@@ -2845,7 +2833,7 @@ function completeStreamItem(
28452833
(error: unknown) => {
28462834
incrementalContext.completed = true;
28472835
return {
2848-
errors: withError(incrementalContext.errors, error as GraphQLError),
2836+
errors: [...incrementalContext.errors, error as GraphQLError],
28492837
};
28502838
},
28512839
);
@@ -2882,7 +2870,7 @@ function completeStreamItem(
28822870
} catch (error) {
28832871
incrementalContext.completed = true;
28842872
return {
2885-
errors: withError(incrementalContext.errors, error),
2873+
errors: [...incrementalContext.errors, error],
28862874
};
28872875
}
28882876

@@ -2911,7 +2899,7 @@ function completeStreamItem(
29112899
(error: unknown) => {
29122900
incrementalContext.completed = true;
29132901
return {
2914-
errors: withError(incrementalContext.errors, error as GraphQLError),
2902+
errors: [...incrementalContext.errors, error as GraphQLError],
29152903
};
29162904
},
29172905
);
@@ -2922,7 +2910,7 @@ function completeStreamItem(
29222910
}
29232911

29242912
function buildStreamItemResult(
2925-
errors: ReadonlyArray<GraphQLError> | undefined,
2913+
errors: ReadonlyArray<GraphQLError>,
29262914
result: GraphQLWrappedResult<unknown>,
29272915
): StreamItemResult {
29282916
const {

src/execution/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ export interface StreamItemResult {
252252
| ReadonlyArray<DeferredFragmentRecord>
253253
| undefined;
254254
incrementalDataRecords?: ReadonlyArray<IncrementalDataRecord> | undefined;
255-
errors?: ReadonlyArray<GraphQLError> | undefined;
255+
errors?: ReadonlyArray<GraphQLError>;
256256
}
257257

258258
export type StreamItemRecord = ThunkIncrementalResult<StreamItemResult>;

0 commit comments

Comments
 (0)