Basically, I wrote this function Q.getter() which wraps any function and turns it into a smart getter, which does caching, throttling and queueing as needed. Pardon me but I did it 10 years ago before Promises were standard: https://github.com/EGreg/Q.js
Anyway, the caching part uses Q.Cache, something I built, but my question is very general. So when a reply comes in, I basically have an option to the Q.getter():
"prepare" - optionally used to feed the data sent on the wire to a constructor, so you get back an object
And then inside Q.getter() I stuff this object into the cache.
So far so good, but here is the issue: the cache can often depend on a number of things. For example a cached User Avatar may change when I update a User Icon stream. What I do now is have functions like _updateUserAvatar() every time a stream changes. Then it checks the name of the stream, and updates the cache.
As another example, when a new message comes in for a stream, I reach into the cache and update the stream's messageCount. I do these kinds of updates so I don't have to go fetch the stream again.
Basically every time some information is pushed from the server, or comes as a reply to some request, I mutate the cached objects on the client side as long as they exist, so they match the latest view of the server object.
And sometimes, I maintain several caches, for example when I call Q.Streams.get(p, n, {withMessages: 10)}) or Q.Streams.get(p, n, {withParticipants: 30, withMessages: 20}) vs just Q.Streams.get(p, n); That's because the caches are keyed automatically by Q.getter() to the JSON-encoded parameters passed to the function. So there is no concept that I should be aggregating the cached objects into one data tree or something, like
{stream: {messages: ..., participants: ...} }
This seems messy and has a lot of brittle code, and I was wondering what a better architecture would be. Would I make a generic mechanism that would aggregate objects and not duplicate caches just because the parameters to the function are different? Or is there a completely better way to do this?