-
Notifications
You must be signed in to change notification settings - Fork 20.6k
CSS: Drop the cache in finalPropName #5583
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
I would prefer to keep the cache, but if you go this way instead, you could go even further and inline the Just be aware the Code suggestion// Returns a potentially-mapped vendor-prefixed property
export function finalPropName( name ) {
// Check for unprefixed property names
if ( name in emptyStyle ) {
return name;
}
// Check for vendor-prefixed property names
var capName = name[ 0 ].toUpperCase() + name.slice( 1 ),
i = cssPrefixes.length;
while ( i-- ) {
var prefixedName = cssPrefixes[ i ] + capName;
if ( prefixedName in emptyStyle ) {
return prefixedName;
}
}
// If no matching property is found, return the original name
return name;
} Fun fact: I discussed the above function with an AI, and it proposed adding exactly the same cache we're talking about here, even though I hadn't asked for it. It even provided a flawless code for it. |
The cache no longer provides much value (I'm not 100% sure it ever did). Ironically, the suggestion you got from AI could very well be from training on previous versions of jQuery. But, I like your suggestion to inline |
I have the whole context of the conversation with the AI, and the code it generated has a distinctive coding style. I'm certain the result doesn't derive from past jQuery code; instead, the AI figured out that the results could be cached and generated code that perfectly accomplishes it. |
There's no way to be certain of that, even if the code formatting is different. The AI was likely trained on at least some jQuery code given its ubiquity, but that's just an educated guess. Still, it's irrelevant to question of the usefulness of the cache. |
Inlining the
|
Ah, no, this was because the dirty state has a different version string with The final size difference is in favor:
I updated the PR. |
d426bda
to
d1ce9e6
Compare
@vlakoff Caching is not always beneficial. We have two possible outcomes:
For these reasons, we felt |
Caution: The PR is currently erroneous. As I wrote above:
Currently, the |
Why do we need to preserve the original |
Lookup is faster on a plain object than on the style property (instance of CSSStyleDeclaration). Both are fast, but the former is significantly faster (sorry, already deleted my local benchmarks). I suppose the function may be called a lot, and gains add up.
Agree that prefixed properties are becoming increasingly rare. Actually, I didn't even consider them when thinking about performance. What we care about are the unprefixed names, which make up 99% of the cases.
Fallback if the supplied value is not a recognized property name. I don't know where this happens in real situations, but I certainly would not risk removing this fallback. |
It’d be good to see some benchmarks to see what numbers we’re talking about. You’re right about the fallback; I need to check if there are any measurable consequences of this and if the answer’s yes, add a test for this. |
I thought so too. |
I suspect you're right about this, and probably by a lot. But, the question isn't, which is faster? The question is, is it fast enough without the cache, which might just take up space? Considering we've been without the cache for most properties (i.e. the ones that don't have a vendor prefix) since 3.4.0 and haven't seen evidence that it affects real world use cases, I doubt adding back the cache is necessary. |
Off topic, but the compare size version regex wasn't accounting for the |
Good news, I found back my benchmark: Benchmark code( function () {
const nb = 100000;
const emptyStyle = document.createElement( "div" ).style;
const finalProps = {};
finalProps.color = "color";
const T1 = new Date();
for ( let i = nb; i--; ) {
if ( "color" in finalProps ) {}
}
const T2 = new Date();
for ( let i = nb; i--; ) {
if ( "color" in emptyStyle ) {}
}
const T3 = new Date();
console.log( T2 - T1 );
console.log( T3 - T2 );
} )(); Results for 10,000,000 iterations (in ms, lower is better) on Chrome:
The number of iterations is quite high. Although the former is significantly faster, both are very fast. Same benchmark (10,000,000 iterations) on Firefox:
… Agree the cache can be removed. |
Regarding the benchmark, it's even better - we don't expose these APIs publicly so their raw execution doesn't matter - it only matters how it influences public APIs. The real difference would be even lower. |
I started wondering - do we need to auto-add vendor prefixes in 4.x at all? In the past, this was a godsend - instead of calling the I run a small script in supported browsers to detect prefixed CSS props that don't have the identically named unprefixed version and I got the following:
If you look closer, e.g. at Chrome, you'll notice lots of these properties fall into one of the following buckets:
There's also |
More details in a separate comment, so that it's easier to skip it: The script I used for the detection(() => {
'use strict';
const cssPrefixes = ['webkit', 'Moz', 'ms'];
const prefixedProps = new Map();
const emptyStyle = document.createElement('div').style;
function unprefix(prop, prefix) {
const withoutPrefix = prop.slice(prefix.length);
return withoutPrefix[ 0 ].toLowerCase() + withoutPrefix.slice( 1 );
}
for (const prefix of cssPrefixes) {
prefixedProps.set(prefix, new Set());
}
for (const prop in emptyStyle) {
for (const prefix of cssPrefixes) {
if (prop.startsWith(prefix)
&& !(unprefix(prop, prefix) in emptyStyle)) {
prefixedProps.get(prefix).add(prop);
}
}
}
for (const [prefix, propsForPrefix] of prefixedProps) {
console.log(`props for prefix ${prefix}`, propsForPrefix);
}
})(); The list of detected `-webkit-` properties in Chrome
The list of detected `-moz-` properties in Firefox
The list of detected `-webkit-` properties in Firefox
The list of detected `-webkit-` properties in Safari
The list of detected `-ms-` properties in IE 11
|
I have an infamous example:
Refs: |
I just noticed you already mentioned that one specifically:
Personally, I use this property quite often, and without jQuery, I have to handle both the unprefixed and |
Yeah, |
I reverted locally to the
Fluctuations in Brotli sizes are pretty interesting. But the more popular no-module builds are larger, so using two functions makes sense, I think. |
d1ce9e6
to
0aedc9d
Compare
PR updated. |
The `finalPropName` util caches properties detected to require a vendor prefix. This used to cache unprefixed properties as well, but it was reported that this logic broke accidentally during a refactor. Since fewer & fewer properties require a vendor prefix and caching a few basic checks likely has negligible perf benefits, opt to saving a few bytes and remove the cache. Ref jquerygh-5582
e2e0538
to
4c97827
Compare
Summary
The
finalPropName
util caches properties detected to require a vendor prefix. This used to cache unprefixed properties as well, but it was reported that this logic broke accidentally during a refactor. Since fewer & fewer properties require a vendor prefix and caching a few basic checks likely has negligible perf benefits, opt to saving a few bytes and remove the cache.Ref gh-5582
Size comparison:
Checklist
New tests have been added to show the fix or feature worksIf needed, a docs issue/PR was created at https://github.com/jquery/api.jquery.com