Commit 2eb9f83
authored
perf(editor): cache getRenderingShapes sort permutation (tldraw#8784)
In order to keep `editor.getRenderingShapes()` cheap on busy canvases,
this PR caches the sort permutation by id. When the set of ids on the
page hasn't changed since the last call (the common case while drawing —
only props change, not the id set), we skip `Array.sort(sortById)` and
place each entry at its known sorted position in O(N) instead of O(N log
N).
Tracing on Chrome OS at 300 shapes showed `sortById` self-time at ~2.3
ms per call, ~70 ms/sec during drawing. After this change, the same call
takes ~0.1 ms on the cache-hit path (~23× faster).
Stacks with the other in-flight perf work:
- tldraw#8778 — incremental b64 encode and prefix-decode cache
- spatial index epoch + `notVisibleShapes` short-circuit (separate PR)
### Correctness
`sortById` is a deterministic, stateless string comparator on shape ids.
The sorted order of an array is uniquely determined by its set of ids
(ids are unique within a page). So if the cached `Map<id,
sortedPosition>` has the same size as the new array and every new id is
present in the cache, the cached permutation produces exactly the same
result as `Array.sort(sortById)`. If any id is missing, or the size
differs, we fall through to the slow path: full sort, rebuild cache.
### Change type
- [x] `improvement`
### Test plan
1. Draw, drag, and select shapes on a page with many shapes (300+);
ordering of overlapping shapes should be unchanged.
2. Add and delete shapes; the sort cache rebuilds on the first call
after the id set changes.
3. Check that `<iframe>`-style shapes (e.g. embeds) don't re-mount when
sibling shapes update — the DOM-key stability is the whole reason for
the sort, and the cache must preserve it.
- [x] Unit tests
### Release notes
- Faster pointer events on busy canvases — `getRenderingShapes()` skips
its sort step when only shape props (not the id set) have changed.
### Code changes
| Section | LOC change |
| --------------- | ---------- |
| Core code | +31 / -1 |1 parent 5385f0a commit 2eb9f83
1 file changed
Lines changed: 41 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
328 | 328 | | |
329 | 329 | | |
330 | 330 | | |
| 331 | + | |
| 332 | + | |
331 | 333 | | |
332 | 334 | | |
333 | 335 | | |
| |||
4730 | 4732 | | |
4731 | 4733 | | |
4732 | 4734 | | |
4733 | | - | |
| 4735 | + | |
| 4736 | + | |
| 4737 | + | |
| 4738 | + | |
| 4739 | + | |
| 4740 | + | |
| 4741 | + | |
| 4742 | + | |
| 4743 | + | |
| 4744 | + | |
| 4745 | + | |
| 4746 | + | |
| 4747 | + | |
| 4748 | + | |
| 4749 | + | |
| 4750 | + | |
| 4751 | + | |
| 4752 | + | |
| 4753 | + | |
| 4754 | + | |
| 4755 | + | |
| 4756 | + | |
| 4757 | + | |
| 4758 | + | |
| 4759 | + | |
| 4760 | + | |
| 4761 | + | |
| 4762 | + | |
| 4763 | + | |
| 4764 | + | |
| 4765 | + | |
| 4766 | + | |
| 4767 | + | |
| 4768 | + | |
| 4769 | + | |
| 4770 | + | |
| 4771 | + | |
4734 | 4772 | | |
4735 | 4773 | | |
| 4774 | + | |
| 4775 | + | |
4736 | 4776 | | |
4737 | 4777 | | |
4738 | 4778 | | |
| |||
0 commit comments