Skip to content

Commit d73d9dc

Browse files
mfreed7chromium-wpt-export-bot
authored andcommitted
Add append_to argument to Clone() to avoid extra InsertedInto calls
Because of the order of operations for Clone(), previous to this CL, the typical sequence would be: 1. Clone the element 2. Clone the children of the element (recursing to step #1). 3. AppendChild() each cloned child to its parent cloned element. 4. (in the caller of Clone) AppendChild the cloned element to its eventual parent. Because each AppendChild triggers a call to Node::InsertedInto() for *all descendants of the appended element* [1], the fact that the tree is constructed bottom-up (leaf nodes first) means that InsertedInto() is called N^2 times, where N is the depth of the cloned tree. Because clone-and-append is a very common pattern, this CL adds an `append_to` argument to `Clone()`, which appends to the parent before appending the children. This CL also adds a perf test for this scenario (cloning a deep tree). Locally, on a debug build, this test gives 0.13 runs/s before this CL, and 0.40 runs/s after, for a 3.1X speedup. [1] https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/dom/container_node.cc;l=1006;drc=5d60017dba57e86d477634812e1340127734f8a7 Bug: 1453291 Change-Id: Icdd75c45aa5ecc4fe8bb5d1ff0b7a2b27bec2171 Cq-Do-Not-Cancel-Tryjobs: true Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4728983 Reviewed-by: David Baron <dbaron@chromium.org> Commit-Queue: David Baron <dbaron@chromium.org> Auto-Submit: Mason Freed <masonf@chromium.org> Commit-Queue: Mason Freed <masonf@chromium.org> Cr-Commit-Position: refs/heads/main@{#1177922}
1 parent ad7dbb3 commit d73d9dc

File tree

1 file changed

+18
-0
lines changed

1 file changed

+18
-0
lines changed

custom-elements/form-associated/form-disabled-callback.html

+18
Original file line numberDiff line numberDiff line change
@@ -132,5 +132,23 @@
132132
fieldset.disabled = false;
133133
assert_array_equals(container.querySelector('my-control').disabledHistory(), [true]);
134134
}, 'Toggling "disabled" attribute on a <fieldset> does not trigger a callback on disabled custom element descendant');
135+
136+
test(() => {
137+
const template = document.createElement('template');
138+
template.innerHTML = '<my-control></my-control>';
139+
const container = document.createElement('fieldset');
140+
document.body.appendChild(container);
141+
container.disabled = true;
142+
container.appendChild(template.content.cloneNode(true));
143+
assert_array_equals(container.querySelector('my-control').disabledHistory(), [true]);
144+
}, 'Callback triggered during a clone/append operation, with disabled state provided by ancestor');
145+
146+
test(() => {
147+
const container = document.createElement('div');
148+
document.body.appendChild(container);
149+
container.innerHTML = '<fieldset disabled><my-control></my-control></fieldset>';
150+
const clone = container.cloneNode(true);
151+
assert_array_equals(container.querySelector('my-control').disabledHistory(), [true]);
152+
}, 'Callback triggered during a clone operation, with disabled state provided by ancestor');
135153
</script>
136154
</body>

0 commit comments

Comments
 (0)