-
-
Notifications
You must be signed in to change notification settings - Fork 96
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
[Optimization] Cache prev values in closure instead of recordPropMetadata
#297
Comments
<script type="module">
import { Bench } from 'https://esm.sh/tinybench'
function recordPropMetadata(el, key, value) {
const metadata = getMetadata(el)[0]
const prev = metadata[key]
if (prev !== value) metadata[key] = value
return prev
}
function getMetadata(el) {
return el.$$metadata || (el.$$metadata = [{}, {}])
}
function setAttr(el, key, value) {
const oldVal = recordPropMetadata(el, key, value)
if (value !== oldVal) {
if (value != null) {
el.setAttribute(key, value)
} else {
el.removeAttribute(key)
}
}
}
function setAttr2(el, key, oldVal, value) {
if (value !== oldVal) {
if (value != null) {
el.setAttribute(key, value)
} else {
el.removeAttribute(key)
}
}
}
function setAttr3(el, key, value) {
if (value != null) {
el.setAttribute(key, value)
} else {
el.removeAttribute(key)
}
}
function setClass(el, value) {
const prev = recordPropMetadata(el, 'class', value)
if (value !== prev && (value || prev)) {
el.className = value
}
}
function setClass2(el, prev, value) {
if (value !== prev && (value || prev)) {
el.className = value
}
}
function setClass3(el, value) {
if ((value || prev)) {
el.className = value
}
}
const updateOne = (() => {
const n1 = document.createElement('div')
const n2 = document.createElement('div')
const n3 = document.createElement('div')
const n4 = document.createElement('div')
return val => {
setClass(n1, val)
setAttr(n1, 'id', val)
setClass(n2, val)
setAttr(n3, 'id', val)
setClass(n4, val)
}
})()
const updateTwo = (() => {
const n1 = document.createElement('div')
const n2 = document.createElement('div')
const n3 = document.createElement('div')
const n4 = document.createElement('div')
let cls, id, cls2, id2, cls3
return val => {
setClass2(n1, cls, (cls = val))
setAttr2(n1, 'id', id, (id = val))
setClass2(n2, val, (cls2 = val))
setAttr2(n3, 'id', val, (id2 = val))
setClass2(n4, val, (cls3 = val))
}
})()
const updateThree = (() => {
const n1 = document.createElement('div')
const n2 = document.createElement('div')
const n3 = document.createElement('div')
const n4 = document.createElement('div')
let cls, id, cls2, id2, cls3
return val => {
cls !== val && setClass3(n1,(cls = val))
id !== val && setAttr3(n1, 'id',(id = val))
cls2 !== val && setClass3(n2,(cls2 = val))
id2 !== val && setAttr3(n3, 'id', (id2 = val))
cls3 !== val && setClass3(n4, (cls3 = val))
}
})()
const bench = new Bench({ name: 'old value handling for set ops', time: 100 })
let i
bench
.add('in closure', () => {
updateTwo(i++ % 5 ? 'foo' : 'bar')
})
.add('in metadata', () => {
updateOne(i++ % 5 ? 'foo' : 'bar')
})
.add('in closure 2', () => {
updateThree(i++ % 5 ? 'foo' : 'bar')
})
await bench.run()
console.log(bench.name)
const output = JSON.stringify(bench.table(), null, 2)
document.getElementById('output').textContent = output
</script>
<pre id="output"></pre> result in chrome
|
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Currently prop-setting helpers do this:
recordPropMetadata
has noticeable overhead on every call:Changes Needed
For template
Current codegen:
Should be changed to (storing prev update values in the local closure):
And in the relevant helpers,
prev
value should come from the argument instead of element metadata.Benchmark
A simple benchmark that simulate a typical vapor update function:
Result in Chrome:
The text was updated successfully, but these errors were encountered: