-
-
Notifications
You must be signed in to change notification settings - Fork 4.5k
chore: check namespace inside set attributes #15443
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
Conversation
Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com>
…ear in changelog
…s/shared/element.js
🦋 Changeset detectedLatest commit: d7caac0 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Note that this will make the code longer for regular elements, as it currently use the default value of these params. Also, the generated code on the PR 15413 is longuest because it use long attribute names, but that should be reduced by minifier. Perhaps another alternative is to use an unique flag to group boths values into one : $.element(node, () => 'div', false, (
$$element,
$$anchor,
$$flag
) => {
$.set_attributes($$element, null, { fooBar: 42 }, undefined, $$flag);
}); With something like that inside set_attributes() : const preserve_attribute_case = flags & PRESERVE_ATTRIBUTE_CASE;
const is_custom_element = flags & CUSTOM_ELEMENT; |
skip_warning = false | ||
) { | ||
export function set_attributes(element, prev, next, css_hash, skip_warning = false) { | ||
var is_custom_element = element.nodeName.includes('-'); |
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.
Can't we cache this in the internal __attributes
object somehow? The namespace check is actually quite expensive it seems benchmarking.
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.
good idea, done
The flags idea is smart, though doing it inside |
The flags can have a default value or be determined at compile time in most case like actually for regular element With this PR we will now check that at runtime instead of compile time... |
This is a lot better now, having to do that check for every attribute that has properties would have had an impact on performance. However, I think passing in a single flag would also work well for the simple element case, the flag is to say that we need a runtime check for those two properties. In the vast majority of cases these never need to be checked for. So if we optimise for that case then we likely never have to do any work here at all. |
return /** @type {Record<string | symbol, unknown>} **/ ( | ||
// @ts-expect-error | ||
element.__attributes ??= { | ||
[IS_CUSTOM_ELEMENT]: element.nodeName.includes('-'), |
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 would be good to get an idea from our website or something how many times this is normally called. If it's a lot then we probably want to avoid it for the simple element case – which is the vast majority of elements.
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.
For svelte.dev it's 147, for svelte.dev/playground it's 260, for svelte.dev/tutorial it's 302. If you interact with the search box it will increase by a few hundred. Obviously if you had a very large list then it would be more, but the upshot is that we're typically talking about hundreds of operations.
I don't know if this is a valid microbenchmark, but on this M1 MBP I can run the check 10,000 times (i.e. run(1e4)
before it takes more than a single millisecond:
function run(i = 1e6) {
console.time('test');
let div = document.createElement('div');
while (i--) {
div.nodeName.includes('-');
div.namespaceURI === 'http://www.w3.org/1999/xhtml';
}
console.timeEnd('test');
}
So... it's measurable, but seems pretty negligible. I don't know, what do you think?
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.
What if you create the elements and attach them to the DOM and then test the lookup cost? It seems more realistic to check attached elements and to remove the cost of creating the DOM element from the benchmark.
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.
Makes no real difference
function run(i = 1e6) {
let div = document.createElement('div');
document.body.append(div);
console.time('test');
while (i--) {
div.nodeName.includes('-');
div.namespaceURI === 'http://www.w3.org/1999/xhtml';
}
console.timeEnd('test');
}
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 mean:
function run(i = 1e6) {
const els = Array(1e6);
let s = i;
while (s--) {
let div = document.createElement('div');
document.body.append(div);
els[s] = div;
}
console.time('test');
while (i--) {
const div = els[i];
div.nodeName.includes('-');
div.namespaceURI === 'http://www.w3.org/1999/xhtml';
}
console.timeEnd('test');
}
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.
Still looks good though, let's ship it and if needed we can revisit and optimise in the future.
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.
Try it! The results are basically the same. Though the code above isn't correct, it should be this:
function run(n = 1e6) {
const els = Array(n);
let i = n;
while (i--) {
let div = document.createElement('div');
document.body.append(div);
els[i] = div;
}
console.time('test');
i = n;
while (i--) {
const div = els[i];
div.nodeName.includes('-');
div.namespaceURI === 'http://www.w3.org/1999/xhtml';
}
console.timeEnd('test');
}
Possible alternative to #15413 — results in more compact compiler output — this...
...becomes this...
...instead of this (on
main
)......or this (in #15413):
The trade-off is that we need to determine
is_custom_element
andpreserve_attribute_case
every timeset_attributes
runs. But I think it's worth it for the smaller output and somewhat simpler codeBefore submitting the PR, please make sure you do the following
feat:
,fix:
,chore:
, ordocs:
.packages/svelte/src
, add a changeset (npx changeset
).Tests and linting
pnpm test
and lint the project withpnpm lint