-
Notifications
You must be signed in to change notification settings - Fork 40
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
fix: improve addChild and path performance #1891
Conversation
@@ -77,7 +77,12 @@ export class Node { | |||
* Components are separated by '/'. | |||
*/ | |||
public get path(): string { | |||
const components = this.scopes.filter(c => c.node.id).map(c => c.node.id); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Calling filter
generates one array, and calling map
after creates another array. It should be slightly faster to create a single array and perform filtering inside a for loop.
@@ -417,21 +422,13 @@ export class Node { | |||
throw new Error(`Cannot add children to "${this.path}" during synthesis`); | |||
} | |||
|
|||
if (childName in this._children) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From what I tested, array access is slightly faster than using the "in" operator
if (!childName && this.id) { | ||
throw new Error(`cannot add a nameless construct to the named scope: ${this.path}`); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this if branch can get called. Here's my reasoning:
addChild
is only called if a non-nullscope
is passed to theNode
constructor.- if a non-null
scope
is passed to theNode
constructor, andthis.id
has a falsey value (likeundefined
or an empty string), then an error will be thrown in theNode
constructor beforeaddChild
is called. - based on (1) and (2), when
addChild
is called, it's guaranteed thatchildName
will not be a falsey value - the if statement's body only executes if childName takes on a falsey value
I tried coming up with a test case that would actually throw this error but I don't think there's a way.
if (Object.keys(this._children).length > 1 && Object.keys(this._children).filter(x => !x).length > 0) { | ||
throw new Error('only a single construct is allowed in a scope if it has an empty name'); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also don't think this branch can ever get called. Here was my reasoning:
- From my other comment,
childName
will never take on a falsey value (like an empty string). - From (1), the line
this._children[childName] = childl
can never add falsey values as keys tothis._children
. - There are no other lines of code that add new keys to
this._children
. - Therefore,
this._children
will always have keys with truthy values, soObject.keys(this._children).filter(x => !x)
can never have a length greater than 0.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ha thanks for that!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
Improve the performance of the
constructs
library by removing several branches in the library's hot paths and switching to some more performant operations.On my laptop, the benchmark I used (shared in a gist here) takes about 5.0-5.3 seconds with the old version of constructs, and about 1.1-1.2 seconds with the new version of constructs.
Misc:
test
folder.npmignore
to reduce the package's npm footprint.