-
Notifications
You must be signed in to change notification settings - Fork 382
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: avoid using a stack in traverseAndSetElements
#4181
Conversation
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.
This is really neat! It makes me wonder whether we can apply this to some of the other depth-first traversals we do in the engine (and/or whether those traversals are hot enough to warrant the effort).
while (isNull((sibling = nextSibling(node)))) { | ||
if (process.env.NODE_ENV !== 'production') { | ||
// We should never traverse up to the root. We should exit early due to numFoundParts === numParts. | ||
assert.isFalse( |
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.
Is there a specific situation you're thinking about that warrants this assertion, and should we have a test case for it?
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.
It's not really possible to hit, but I'm concerned we could recurse up past the root if (somehow) there were more parts to be found. This happened in the past when we messed up and forgot to include comment nodes when preserve-comments
is on.
Yep, another one is |
Details
This improves the
js-framework-benchmark
'screate-10k
test by 8-10% in Chrome/Firefox and 4-9% in Safari. It does so by avoiding either recursion or a stack (array) by using a loop withfirstChild
/nextSibling
/parentNode
.Click to see benchmark results
I was kind of concerned that adding
parentNode
would cause a perf regression in synthetic shadow (due to patches), but I tested manually in synthetic shadow (nolanlawson@4536c23), and it's faster there as well:Click to see
I also tried using a
TreeWalker
(nolanlawson@303e7b7), since this is what Lit does. However, I found that theTreeWalker
is ~0.5% slower than the loop:Click to see
(TreeWalker is this-change, loop is tip-of-tree)
We may still want to consider the
TreeWalker
someday, due to the possible benefits in synthetic shadow (which does not patchTreeWalker
at all), and because it's slightly less code.One major downside, though, is that we'd need to implement a
TreeWalker
shim for@lwc/engine-server
. For that reason, and because this is the optimal solution forjs-framework-benchmark
, I'm proposing this for now.Does this pull request introduce a breaking change?
Does this pull request introduce an observable change?