Let's jump into JavaScript VM details to see why and how to guard against this VM de-opt:
🧵🪡🧶
The first thing to understand is that JavaScript has two representations for numbers:
- Integers: Fast path
- Floats (IEEE 754): Slower path
Integers are stored as “Two's complement” and can't have `-0`, but Floats can!
Let's assume: `x` is an Integer and `x = 0`
`0-x` => `0-0 => 0`, Result is `0` (Integer) Perfect!
`-x` => negate `x`.
- For any non-zero value, the result is an Integer.
- But for `0`, the result is `-0`. But integers can't have `-0`, So JavaScript stores it as a Float `-0`.
Why is this a de-opt:
1) Array access requires an Integer. So VM has to guard for Floats and convert Float (-0) into Integer(0);
2) VMs have special "fast" arrays for all integers but use a more generic (slower) array for an array of mixed types (such as Integers and Floats)
Different browsers have different perf penalties for this, but my tests show a 3-10x slow down on Apple M1:
JSX could have been 2x faster if it was designed more optimally for JS VMs!
Let's see what design decisions make JSX slow and how we could speed it up.
🧵🪡🧶
There are two issues with tcurrent JSX transpilation:
1. The use of object-literal for properties causes megamorphic access on read. 2. Using variable args requires conversion to an array in `h()` function.
Let’s try an alternative transpilation format: 1. Arrays are always monomorphic 2. Key/Value pairs can be stored at odd/even locations 3. Children are in an array
Teamworks are essential! @adamdbradley , @manucorporat and the @QwikDev community are amazing! Before then, I was part of the Angular Team and community that were equally amazing. In both cases, things would not happen without them!
useSignal() is the future of web frameworks and is a better abstraction than useState(), which is showing its age.
🧵🪡🧶
useState() returns the value "in time" rather than the state "over time" it represents. This can lead to problems when value is captured in closures such as useEffect().
useState() => value + setter
useSignal() => getter + setter
Value is problematic because you must remember to pass it down every time it changes. A getter (like the setter) never changes, and so it only needs to be passed once.