b5aff00c89
This PR does a few things to help with performance:
1. Instead of doing changes on raf we now do them 60 times per second.
This limits the number of updates on high refresh rate screens like the
iPad. With the current code this only applied to the history updates (so
when you subscribed to the updates), but the next point takes this a bit
futher.
2. We now trigger react updates 60 times per second. This is a change in
`useValue` and `useStateTracking` hooks.
3. We now throttle the inputs (like the `pointerMove`) in state nodes.
This means we batch multiple inputs and only apply them at most 60 times
per second.
We had to adjust our own tests to pass after this change so I marked
this as major as it might require the users of the library to do the
same.
Few observations:
- The browser calls the raf callbacks when it can. If it gets
overwhelmed it will call them further and further apart. As things call
down it will start calling them more frequently again. You can clearly
see this in the drawing example. When fps gets to a certain level we
start to get fewer updates, then fps can recover a bit. This makes the
experience quite janky. The updates can be kinda ok one second (dropping
frames, but consistently) and then they can completely stop and you have
to let go of the mouse to make them happen again. With the new logic it
seems everything is a lot more consistent.
- We might look into variable refresh rates to prevent this overtaxing
of the browser. Like when we see that the times between our updates are
getting higher we could make the updates less frequent. If we then see
that they are happening more often we could ramp them back up. I had an
[experiment for this
here](4834863966 (diff-318e71563d7c47173f89ec084ca44417cf70fc72faac85b96f48b856a8aec466L30-L35)
).
Few tests below. Used 6x slowdown for these.
# Resizing
### Before
https://github.com/tldraw/tldraw/assets/2523721/798a033f-5dfa-419e-9a2d-fd8908272ba0
### After
https://github.com/tldraw/tldraw/assets/2523721/45870a0c-c310-4be0-b63c-6c92c20ca037
# Drawing
Comparison is not 100% fair, we don't store the intermediate inputs
right now. That said, tick should still only produce once update so I do
think we can get a sense of the differences.
### Before
https://github.com/tldraw/tldraw/assets/2523721/2e8ac8c5-bbdf-484b-bb0c-70c967f4541c
### After
https://github.com/tldraw/tldraw/assets/2523721/8f54b7a8-9a0e-4a39-b168-482caceb0149
### Change Type
- [ ] `patch` — Bug fix
- [ ] `minor` — New feature
- [x] `major` — Breaking change
- [ ] `dependencies` — Changes to package dependencies[^1]
- [ ] `documentation` — Changes to the documentation only[^2]
- [ ] `tests` — Changes to any test code only[^2]
- [ ] `internal` — Any other changes that don't affect the published
package[^2]
- [ ] I don't know
[^1]: publishes a `patch` release, for devDependencies use `internal`
[^2]: will not publish a new version
### Release Notes
- Improves the performance of rendering.
---------
Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
68 lines
1.8 KiB
TypeScript
68 lines
1.8 KiB
TypeScript
export {
|
|
areArraysShallowEqual,
|
|
compact,
|
|
dedupe,
|
|
last,
|
|
minBy,
|
|
partition,
|
|
rotateArray,
|
|
} from './lib/array'
|
|
export {
|
|
Result,
|
|
assert,
|
|
assertExists,
|
|
exhaustiveSwitchError,
|
|
promiseWithResolve,
|
|
type ErrorResult,
|
|
type OkResult,
|
|
} from './lib/control'
|
|
export { debounce } from './lib/debounce'
|
|
export { annotateError, getErrorAnnotations } from './lib/error'
|
|
export { FileHelpers } from './lib/file'
|
|
export { noop, omitFromStackTrace, throttle } from './lib/function'
|
|
export { getHashForBuffer, getHashForObject, getHashForString, lns } from './lib/hash'
|
|
export { getFirstFromIterable } from './lib/iterable'
|
|
export type { JsonArray, JsonObject, JsonPrimitive, JsonValue } from './lib/json-value'
|
|
export { MediaHelpers } from './lib/media'
|
|
export { invLerp, lerp, modulate, rng } from './lib/number'
|
|
export {
|
|
areObjectsShallowEqual,
|
|
deepCopy,
|
|
filterEntries,
|
|
getOwnProperty,
|
|
hasOwnProperty,
|
|
mapObjectMapValues,
|
|
objectMapEntries,
|
|
objectMapFromEntries,
|
|
objectMapKeys,
|
|
objectMapValues,
|
|
} from './lib/object'
|
|
export { PngHelpers } from './lib/png'
|
|
export { type IndexKey } from './lib/reordering/IndexKey'
|
|
export {
|
|
ZERO_INDEX_KEY,
|
|
getIndexAbove,
|
|
getIndexBelow,
|
|
getIndexBetween,
|
|
getIndices,
|
|
getIndicesAbove,
|
|
getIndicesBelow,
|
|
getIndicesBetween,
|
|
sortByIndex,
|
|
validateIndexKey,
|
|
} from './lib/reordering/reordering'
|
|
export { sortById } from './lib/sort'
|
|
export {
|
|
clearLocalStorage,
|
|
clearSessionStorage,
|
|
deleteFromLocalStorage,
|
|
deleteFromSessionStorage,
|
|
getFromLocalStorage,
|
|
getFromSessionStorage,
|
|
setInLocalStorage,
|
|
setInSessionStorage,
|
|
} from './lib/storage'
|
|
export { fpsThrottle, throttleToNextFrame } from './lib/throttle'
|
|
export type { Expand, RecursivePartial, Required } from './lib/types'
|
|
export { isDefined, isNonNull, isNonNullish, structuredClone } from './lib/value'
|
|
export { warnDeprecatedGetter } from './lib/warnDeprecatedGetter'
|