v5.3.0 #787
markerikson
started this conversation in
General
v5.3.0
#787
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
This feature release adds a
maxSizeoption toweakMapMemoizeto bound cache growth, adds a new development-mode check that warns when a selector's cache grows without bound, improves memoization performance, removes the experimentalunstable_autotrackMemoize, and updates our TypeScript support matrix and documentation.Changelog
maxSizeOption forweakMapMemoizeweakMapMemoizehas been the default memoizer since v5.0, and its main benefit is the infinite cache size. Prior to v5, selector instances had a default cache size of 1, which meant having to create unique selector instances per component when sharing selectors that took varying arguments like IDs.weakMapMemoizememoizes based on all arguments, so it eliminated the extra setup work and just stores all cached values.However, that behavior can also effectively turn into a memory leak depending on what state and arguments are passed in and how they're used in the UI.
weakMapMemoizenow accepts amaxSizeoption that bounds this growth:This shares the same
maxSizeoption name as the earlierlruMemoize, but has different behavior. Rather than an LRU eviction, this is a "generational" swap (kind of like a double buffer). When the cache hits its max size, it's swapped out with an empty version and starts over at 0 entries. So, there's effectively at most 2 *maxSizeitems in memory at any time. IfmaxSizeis not enabled, there's no additional logic or performance overhead. If you do need LRU-style behavior, uselruMemoizeinstead.Note that bounding a
createSelectorselector requires passingmaxSizein bothmemoizeOptionsandargsMemoizeOptions, since the two memoization levels have separate caches. See themaxSizedocs for details.Thanks to @veksa for proposing this in PR #761 and providing memory test infrastructure that helped verify this behavior.
New
cacheSizeCheckDev-Mode CheckWe've also added an additional dev-mode check alongside the existing
inputStabilityCheckandidentityFunctionCheck. If a memoized function has accumulated over 1000 values for the same args, it logs a warning with the function name and stack trace. By default this runs once per function. Unlike the other two checks, it can only be configured globally, viasetGlobalDevModeChecks({ cacheSizeCheck: 'always' | 'once' | 'never' })Performance Improvements
We've revamped our own performance benchmark suite to give better results with more precision and less noise. That's helped verify some additional performance improvements.
weakMapMemoizenow returns early on a cache hit instead of continuing through bookkeepinglruMemoize's cache lookup was simplified to eliminate unnecessary allocationsThese are small wins on already-fast paths, but did show modest improvements.
Removal of
unstable_autotrackMemoizeWe've removed the experimental
unstable_autotrackMemoizeexport. It was added in v5.0 as an experiment in Glimmer-style dependency tracking, never leftunstable_, and as far as we can tell never saw real adoption. If you were using it, switch toweakMapMemoize(the default) orlruMemoize.TypeScript Support
Our TypeScript support matrix is now 5.6 and up, matching DefinitelyTyped, and CI now tests against TS 6.0.
We've documented on the selector fields that a full cache reset requires clearing both memoization levels:
selector.clearCache()plusselector.memoizedResultFunc.clearCache().We improved types handling in cases where TS strict mode is off (but please migrate to strict behavior as soon as possible!)
Docs Improvements
The API docs got a structural overhaul: every API page now follows a consistent "API Reference / Usage Guide" layout, the dev-checks page was rewritten, and the docs reflect that
weakMapMemoizeis the default memoizer since v5. We've also added some additional usage guidance as well.What's Changed
createSelectorby @veksa in test: paired hot-path benchmark forcreateSelector#770resultEqualityCheckreceiving a clearedWeakRefby @veksa in Add regression test forresultEqualityCheckreceiving a clearedWeakRef#763maxSizeoption forweakMapMemoizeby @markerikson in Add amaxSizeoption forweakMapMemoize#783lastResultbetween tests #569) by @veksa in docs: clarify how to fully clear a selector's cache (#569) #760Full Changelog: v5.2.0...v5.3.0
This discussion was created from the release v5.3.0.
All reactions