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(engine-core): optimize slot iteration #3166

Merged
merged 1 commit into from
Nov 14, 2022
Merged

Conversation

nolanlawson
Copy link
Contributor

@nolanlawson nolanlawson commented Nov 14, 2022

Details

It turns out that 2ada663 and e983223 introduced a perf regression. The dom-ss-slot-update-slotted-content-5k benchmark regressed 16% comparing master to 240. The culprit is this reduce function:

children = slotset.slotAssignments[slotName].reduce((accumulator, vnode) => {

This PR improves the benchmark by 11-12% (comparing this PR to master):

Remote Desktop Picture November 14, 2022 at 9 20 01 AM PST

Improvements:

  • use a for-loop instead of Array.prototype.reduce
  • use ArrayPush instead of ArrayConcat (ArrayConcat creates a brand-new copy of the array, which we don't strictly need)

Does this pull request introduce a breaking change?

  • ✅ No, it does not introduce a breaking change.

Does this pull request introduce an observable change?

  • ✅ No, it does not introduce an observable change.

GUS work item

W-12028575

// Evaluate in the scope of the slot content's owner
// if a slotset is provided, there will always be an owner. The only case where owner is
// undefined is for root components, but root components cannot accept slotted content
setVMBeingRendered(slotset.owner!);
try {
scopedSlotChildren = vnode.factory(data.slotData);
ArrayPush.apply(newChildren, vnode.factory(data.slotData) as VNode[]);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I considered isolating just the factory() call here for readability, but it adds quite a bit of extra code:

const vmBeingRenderedInception = getVMBeingRendered();
let scopedSlotChildren: VNodes | undefined;
setVMBeingRendered(slotset.owner!);
try {
    scopedSlotChildren = vnode.factory(data.slotData);
} finally {
    setVMBeingRendered(vmBeingRenderedInception);
}
if (!isUndefined(scopedSlotChildren)) {
    ArrayPush.apply(newChildren, scopedSlotChildren as VNode[]);
}

Copy link
Contributor

Choose a reason for hiding this comment

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

The return value from the factory need to be spread out and not inserted as-is.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@ravijayaramappa This is Array.push.apply, not ArrayPush.call. So it is being spread out. 🙂

Copy link
Contributor

Choose a reason for hiding this comment

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

🤦 oh yes, my bad.

}
// If the passed slot content is factory, evaluate it and add the produced vnodes
if (assignedNodeIsScopedSlot) {
const vmBeingRenderedInception = getVMBeingRendered();
let scopedSlotChildren: VNodes = [];
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Avoiding creating an extra [] here.

if (vnode) {
const newChildren: VNode[] = [];
const slotAssignments = slotset.slotAssignments[slotName];
for (let i = 0; i < slotAssignments.length; i++) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I didn't check what the fastest way to iterate is (e.g. compared to for (const vnode of slotAssignments) {}. But we do use this pattern in lots of places in the code.

Copy link
Contributor

@divmain divmain left a comment

Choose a reason for hiding this comment

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

This looks reasonable to me.

@nolanlawson nolanlawson merged commit 60c352e into master Nov 14, 2022
@nolanlawson nolanlawson deleted the nolan/optimize-reduce branch November 14, 2022 23:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants