Skip to content

Commit 69d90c6

Browse files
IvanGoncharovleebyron
authored andcommitted
Execute: simplify + speedup (#1286)
* Remove 'completeValueWithLocatedError' * Execute: move promise resolution to the completeValueCatchingError * Remove fat arrow function * Execute: rewrite executeFields to use for-in instead of reduce * Extract locatedFieldError function * extract handleFieldError function * Address @leebyron review comments
1 parent c8358f8 commit 69d90c6

File tree

1 file changed

+51
-92
lines changed

1 file changed

+51
-92
lines changed

src/execution/execute.js

Lines changed: 51 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -506,9 +506,11 @@ function executeFields(
506506
path: ResponsePath | void,
507507
fields: ObjMap<Array<FieldNode>>,
508508
): MaybePromise<ObjMap<mixed>> {
509+
const results = Object.create(null);
509510
let containsPromise = false;
510511

511-
const finalResults = Object.keys(fields).reduce((results, responseName) => {
512+
for (let i = 0, keys = Object.keys(fields); i < keys.length; ++i) {
513+
const responseName = keys[i];
512514
const fieldNodes = fields[responseName];
513515
const fieldPath = addPath(path, responseName);
514516
const result = resolveField(
@@ -518,26 +520,24 @@ function executeFields(
518520
fieldNodes,
519521
fieldPath,
520522
);
521-
if (result === undefined) {
522-
return results;
523-
}
524-
results[responseName] = result;
525-
if (!containsPromise && isPromise(result)) {
526-
containsPromise = true;
523+
524+
if (result !== undefined) {
525+
results[responseName] = result;
526+
if (!containsPromise && isPromise(result)) {
527+
containsPromise = true;
528+
}
527529
}
528-
return results;
529-
}, Object.create(null));
530+
}
530531

531532
// If there are no promises, we can just return the object
532533
if (!containsPromise) {
533-
return finalResults;
534+
return results;
534535
}
535536

536-
// Otherwise, results is a map from field name to the result
537-
// of resolving that field, which is possibly a promise. Return
538-
// a promise that will return this same map, but with any
539-
// promises replaced with the values they resolved to.
540-
return promiseForObject(finalResults);
537+
// Otherwise, results is a map from field name to the result of resolving that
538+
// field, which is possibly a promise. Return a promise that will return this
539+
// same map, but with any promises replaced with the values they resolved to.
540+
return promiseForObject(results);
541541
}
542542

543543
/**
@@ -792,87 +792,53 @@ function completeValueCatchingError(
792792
path: ResponsePath,
793793
result: mixed,
794794
): MaybePromise<mixed> {
795-
// If the field type is non-nullable, then it is resolved without any
796-
// protection from errors, however it still properly locates the error.
797-
if (isNonNullType(returnType)) {
798-
return completeValueWithLocatedError(
799-
exeContext,
800-
returnType,
801-
fieldNodes,
802-
info,
803-
path,
804-
result,
805-
);
806-
}
807-
808-
// Otherwise, error protection is applied, logging the error and resolving
809-
// a null value for this field if one is encountered.
810795
try {
811-
const completed = completeValueWithLocatedError(
812-
exeContext,
813-
returnType,
814-
fieldNodes,
815-
info,
816-
path,
817-
result,
818-
);
796+
let completed;
797+
if (isPromise(result)) {
798+
completed = result.then(resolved =>
799+
completeValue(exeContext, returnType, fieldNodes, info, path, resolved),
800+
);
801+
} else {
802+
completed = completeValue(
803+
exeContext,
804+
returnType,
805+
fieldNodes,
806+
info,
807+
path,
808+
result,
809+
);
810+
}
811+
819812
if (isPromise(completed)) {
820-
// If `completeValueWithLocatedError` returned a rejected promise, log
821-
// the rejection error and resolve to null.
822813
// Note: we don't rely on a `catch` method, but we do expect "thenable"
823814
// to take a second callback for the error case.
824-
return completed.then(undefined, error => {
825-
exeContext.errors.push(error);
826-
return Promise.resolve(null);
827-
});
815+
return completed.then(undefined, error =>
816+
handleFieldError(error, fieldNodes, path, returnType, exeContext),
817+
);
828818
}
829819
return completed;
830820
} catch (error) {
831-
// If `completeValueWithLocatedError` returned abruptly (threw an error),
832-
// log the error and return null.
833-
exeContext.errors.push(error);
834-
return null;
821+
return handleFieldError(error, fieldNodes, path, returnType, exeContext);
835822
}
836823
}
837824

838-
// This is a small wrapper around completeValue which annotates errors with
839-
// location information.
840-
function completeValueWithLocatedError(
841-
exeContext: ExecutionContext,
842-
returnType: GraphQLOutputType,
843-
fieldNodes: $ReadOnlyArray<FieldNode>,
844-
info: GraphQLResolveInfo,
845-
path: ResponsePath,
846-
result: mixed,
847-
): MaybePromise<mixed> {
848-
try {
849-
const completed = completeValue(
850-
exeContext,
851-
returnType,
852-
fieldNodes,
853-
info,
854-
path,
855-
result,
856-
);
857-
if (isPromise(completed)) {
858-
return completed.then(undefined, error =>
859-
Promise.reject(
860-
locatedError(
861-
asErrorInstance(error),
862-
fieldNodes,
863-
responsePathAsArray(path),
864-
),
865-
),
866-
);
867-
}
868-
return completed;
869-
} catch (error) {
870-
throw locatedError(
871-
asErrorInstance(error),
872-
fieldNodes,
873-
responsePathAsArray(path),
874-
);
825+
function handleFieldError(rawError, fieldNodes, path, returnType, exeContext) {
826+
const error = locatedError(
827+
asErrorInstance(rawError),
828+
fieldNodes,
829+
responsePathAsArray(path),
830+
);
831+
832+
// If the field type is non-nullable, then it is resolved without any
833+
// protection from errors, however it still properly locates the error.
834+
if (isNonNullType(returnType)) {
835+
throw error;
875836
}
837+
838+
// Otherwise, error protection is applied, logging the error and resolving
839+
// a null value for this field if one is encountered.
840+
exeContext.errors.push(error);
841+
return null;
876842
}
877843

878844
/**
@@ -904,13 +870,6 @@ function completeValue(
904870
path: ResponsePath,
905871
result: mixed,
906872
): MaybePromise<mixed> {
907-
// If result is a Promise, apply-lift over completeValue.
908-
if (isPromise(result)) {
909-
return result.then(resolved =>
910-
completeValue(exeContext, returnType, fieldNodes, info, path, resolved),
911-
);
912-
}
913-
914873
// If result is an Error, throw a located error.
915874
if (result instanceof Error) {
916875
throw result;

0 commit comments

Comments
 (0)