-
Notifications
You must be signed in to change notification settings - Fork 386
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
Conversation
// 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[]); |
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 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[]);
}
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.
The return value from the factory need to be spread out and not inserted as-is.
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.
@ravijayaramappa This is Array.push.apply
, not ArrayPush.call
. So it is being spread out. 🙂
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.
🤦 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 = []; |
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.
Avoiding creating an extra []
here.
if (vnode) { | ||
const newChildren: VNode[] = []; | ||
const slotAssignments = slotset.slotAssignments[slotName]; | ||
for (let i = 0; i < slotAssignments.length; i++) { |
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 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.
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 looks reasonable to me.
Details
It turns out that 2ada663 and e983223 introduced a perf regression. The
dom-ss-slot-update-slotted-content-5k
benchmark regressed 16% comparingmaster
to 240. The culprit is thisreduce
function:lwc/packages/@lwc/engine-core/src/framework/api.ts
Line 192 in 6376013
This PR improves the benchmark by 11-12% (comparing this PR to
master
):Improvements:
Array.prototype.reduce
ArrayPush
instead ofArrayConcat
(ArrayConcat
creates a brand-new copy of the array, which we don't strictly need)Does this pull request introduce a breaking change?
Does this pull request introduce an observable change?
GUS work item
W-12028575