Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: optimize object creation in decode, fromJSON and fromPartial #457

Merged
merged 3 commits into from
Dec 28, 2021

Conversation

aikoven
Copy link
Collaborator

@aikoven aikoven commented Dec 27, 2021

Creating an object via object spread can be 100 times slower than creating via object literal: https://jsbench.me/0nkxobf9gt/1

Copy link
Owner

@stephenh stephenh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

@aikoven aikoven marked this pull request as ready for review December 28, 2021 07:20
@aikoven
Copy link
Collaborator Author

aikoven commented Dec 28, 2021

@stephenh could you please take another look?

Now all properties are initialized in the base instance, including repeated, optional, map and bytes.

Copy link
Owner

@stephenh stephenh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Great idea to just initialize all the fields while we're at it.

@aikoven aikoven merged commit 70832d3 into stephenh:main Dec 28, 2021
stephenh pushed a commit that referenced this pull request Dec 28, 2021
## [1.96.1](v1.96.0...v1.96.1) (2021-12-28)

### Performance Improvements

* optimize object creation in `decode`, `fromJSON` and `fromPartial` ([#457](#457)) ([70832d3](70832d3))
@stephenh
Copy link
Owner

🎉 This PR is included in version 1.96.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

@webmaster128
Copy link
Collaborator

Nice. We might consider removing the base object creation (create*Message functions) alltogether and simply ensure every field is set in every creator function. WDYT?

@aikoven
Copy link
Collaborator Author

aikoven commented Dec 29, 2021

Nice. We might consider removing the base object creation (create*Message functions) alltogether and simply ensure every field is set in every creator function. WDYT?

Yep, at first I thought that a separate function is needed to prevent duplication (that can result in e.g. increased bundle size). But actually an object literal with default values is only needed in the decode method, and fromJson and fromPartial can simply create an object with actual values right away.

@aikoven aikoven deleted the optimize-object-creation branch December 29, 2021 10:44
Comment on lines -118 to +120
const message = { ...basePleaseChoose } as PleaseChoose;
message.signature = new Uint8Array();
const message = createBasePleaseChoose();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here the creator function is actually nice to have. If it creates all fields, its pretty simple.

Does it make sense to just rename createBasePleaseChoose to createEmptyPleaseChoose and leave it for the decode implementation?

@@ -32,7 +32,9 @@ export interface Child {
name: string;
}

const baseSimple: object = { name: '', age: 0, testField: '', testNotDeprecated: '' };
function createBaseSimple(): Simple {
return { name: '', age: 0, child: undefined, testField: '', testNotDeprecated: '' };
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice to see this creating the correct type with all fields and avoid the unsafe cast that we had before!

@webmaster128
Copy link
Collaborator

actually an object literal with default values is only needed in the decode method, and fromJson and fromPartial can simply create an object with actual values right away

Exactly. This changed a lot over the last months when I migrated many of the assignments to the ?? operator or map such that now in fromPartial/fromJSON each field should be set in exactly one assignment now, either with a value or its default. The base object was valuable before those changes when many fields were set in an if condition only if they where set.

@aikoven
Copy link
Collaborator Author

aikoven commented Dec 29, 2021

By the way, consider that createBaseMsg() is actually the same as Msg.fromPartial({}). Which means that we could extract the logic of fromPartial instead, and use it in encode, thus reducing the generated code size.

A downside of it is that support for outputPartialMethods=false would be more complicated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants