Skip to content

Conversation

@jsnajdr
Copy link
Member

@jsnajdr jsnajdr commented Jan 17, 2018

While trying to use treeSelect to optimize stats/lists/selectors, I found several missing features that make it impossible to use there.

  1. Allow custom getCacheKey function. Stats selectors get a query object that is both used as a key in serialized form and the selector needs to access its properties. We need to allow object arguments and serialize them properly in getCacheKey.

  2. Allow clearing the cache by calling selector.clearCache(). Used by tests.

  3. Don't crash on an invalid WeakMap key when getDependents returns null or other falsy value as one of the dependencies. That happens all the time when the required dependency is being requested from network and its value in Redux state is null in the meantime. I consider all falsy values (null, undefined, false, ...) as identical and map them to one WeakMap key. Discussion whether that's a good idea or whether we should distinguish between them has a great
    bikeshedding potential, but I don't expect any trouble in practice.

While trying to use `treeSelect` to optimize `stats/lists/selectors`, I found
several missing features that make it impossible to use there.

1. Allow custom `getCacheKey` function. Stats selectors get a `query` object
that is both used as a key in serialized form and the selector needs to access
its properties. We need to allow object arguments and serialize them properly
in `getCacheKey`.

2. Allow clearing the cache by calling `selector.clearCache()`. Used by tests.

3. Don't crash on an invalid `WeakMap` key when `getDependents` returns `null`
or other falsy value as one of the dependencies. That happens all the time when
the required dependency is being requested from network and its value in Redux
state is `null` in the meantime. I consider all falsy values (`null`, `undefined`,
`false`, ...) as identical and map them to one `WeakMap` key. Discussion whether
that's a good idea or whether we should distinguish between them has a great
bikeshedding potential, but I don't expect any trouble in practice.
@jsnajdr jsnajdr added [Status] Needs Review The PR is ready for review. This also triggers e2e canary tests and wp-desktop tests automatically. [Type] Performance labels Jan 17, 2018
@jsnajdr jsnajdr self-assigned this Jan 17, 2018

cachedSelector.clearCache = () => {
cache = new WeakMap();
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this needs a comment explaining that WeakMap has no .clear() or we should use an object that is like a WeakMap that does have .clear() - someone's bound to change this otherwise when they don't realize that

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a comment.

/*
* This object will be used as a WeakMap key if a dependency is a falsy value (null, undefined, ...)
*/
const STATIC_FALSY_KEY = {};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually liked the MixedMap @samouri originally had in here. It had clear semantics and didn't require these odd workarounds. Is there real opposition against using MixedMap?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The semantics now is that the dependents are of type Maybe<Object> -- that looks quite clean to me. If I encounter a place where I need the MixedMap, I'll start rooting for it.

Copy link
Contributor

@samouri samouri Jan 17, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we only have a need to support null/undefined/false, then i don't think we should incorporate MixedMap which allowed for unbounded primitives like number and string

* The last map is a regular one because the the key for the last map is the string results of args.join().
*/
function insertDependentKey( map, key, currentIndex, arr ) {
key = key || STATIC_FALSY_KEY;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how would you feel about making this a separate variable so we don't mutate the args? I find this often confusing to read code that does.

function insertDependentKey( map, rawKey, currentIndex, arr ) {
	const key = rawKey || STATIC_FALSY_KEY;

	
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Introduced a weakMapKey variable.

@dmsnell
Copy link
Member

dmsnell commented Jan 17, 2018

Stats selectors get a query object that is both used as a key in serialized form and the selector needs to access its properties

Thanks for iterating here @jsnajdr - I knew these objects would be a valid use-case for object-args.

I'm not super-fond of the name getCacheKey even though it's already in use. I feel like it's more of an id function for a collapsing function. Something like buildKey or buildId or value2key - have you shared any of the confusion with getCacheKey()?

@jsnajdr
Copy link
Member Author

jsnajdr commented Jan 17, 2018

@dmsnell I'm OK with the getCachedKey name and none of the proposed alternatives look particularly attractive 🤷‍♂️

Copy link
Contributor

@samouri samouri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code LGTM, thanks for the improvements @jsnajdr!

One thing I disagree on is the need for a clearCache. It'll only ever be used in tests, and you can easily have this code in beforeEach:

beforeEach(() => {
 selectorToClear = treeSelect(...);
})

I wouldn't block on that though, merge away!

@jsnajdr jsnajdr merged commit fad9a5f into master Jan 18, 2018
@jsnajdr jsnajdr deleted the improve/tree-select branch January 18, 2018 10:00
@sirreal sirreal removed the [Status] Needs Review The PR is ready for review. This also triggers e2e canary tests and wp-desktop tests automatically. label Mar 27, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants