Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Incremental updates using browser cache

The client (an AngularJS application) gets rather big lists from the server. The lists may have hundreds or thousands of elements, which can mean a few megabytes uncompressed (and some users (admins) get much more data).

I'm not planning to let the client get partial results as sorting and filtering should not bother the server.

Compression works fine (factor of about 10) and as the lists don't change often, 304 NOT MODIFIED helps a lot, too. But another important optimization is missing:

As a typical change of the lists are rather small (e.g., modifying two elements and adding a new one), transferring the changes only sounds like a good idea. I wonder how to do it properly.

Something like GET /offer/123/items should always return all the items in the offer number 123, right? Compression and 304 can be used here, but no incremental update. A request like GET /offer/123/items?since=1495765733 sounds like the way to go, but then browser caching does not get used:

  • either nothing has changed and the answer is empty (and caching it makes no sense)
  • or something has changed, the client updates its state and does never ask for changes since 1495765733 anymore (and caching it makes even less sense)

Obviously, when using the "since" query, nothing will be cached for the "resource" (the original query gets used just once or not at all).

So I can't rely on the browser cache and I can only use localStorage or sessionStorage, which have a few downsides:

  • it's limited to a few megabytes (the browser HTTP cache may be much bigger and gets handled automatically)
  • I have to implement some replacement strategy when I hit the limit
  • the browser cache stores already compressed data which I don't get (I'd have to re-compress them)
  • it doesn't work for the users (admins) getting bigger lists as even a single list may already be over limit
  • it gets emptied on logout (a customer's requirement)

Given that there's HTML 5 and HTTP 2.0, that's pretty unsatisfactory. What am I missing?

Is it possible to use the browser HTTP cache together with incremental updates?

like image 553
maaartinus Avatar asked May 26 '17 03:05

maaartinus


People also ask

What is incremental caching?

Incremental caching is a way to limit the refreshing of the local cache of a client to only the changed data of the server, based on a timestamp. For each table that incremental caching is desired for, a timestamp column should be added.

How does browser cache work?

The HTTP cache stores a response associated with a request and reuses the stored response for subsequent requests. There are several advantages to reusability. First, since there is no need to deliver the request to the origin server, then the closer the client and cache are, the faster the response will be.

How do I force browser cache refresh?

But you can bypass the cache and force a complete refresh by using some simple hotkeys: Windows and Linux browsers: CTRL + F5. Apple Safari: SHIFT + Reload toolbar button. Chrome and Firefox for Mac: CMD + SHIFT + R.

Why will you consider clearing my browser cache?

It is a good idea to clear your browser cache because it: prevents you from using old forms. protects your personal information. helps our applications run better on your computer.


1 Answers

I think there is one thing you are missing: in short, headers. What I'm thinking you could do and that would match (most) of your requirements, would be to:

  • First GET /offer/123/items is done normally, nothing special.
  • Subsequents GET /offer/123/items will be sent with a Fetched-At: 1495765733 header, indicating your server when the initial request has been sent.

From this point on, two scenarios are possible.

  • Either there is no change, and you can send the 304.
  • If there is a change however, return the new items since the time stamp previously sent has headers, but set a Cache-Control: no-cache from your response.

This leaves you to the point where you can have incremental updates, with caching of the initial megabytes-sized elements.

There is still one drawback though, that the caching is only done once, it won't cache updates. You said that your lists are not updated often so it might already work for you, but if you really want to push this further, I could think of one more thing.

Upon receiving an incremental update, you could trigger in the background another request without the Fetched-At header that won't be used at all by your application, but will just be there to update your http cache. It should not be as bad as it sounds performance-wise since your framework won't update its data with the new one (and potentially trigger re-renders), the only notable drawback would be in term of network and memory consumption. On mobile it might be problematic, but it doesn't sounds like an app intended to be displayed on them anyway.

I absolutely don't know your use-case and will just throw that out there, but are you really sure that doing some sort of pagination won't work? Megabytes of data sounds a lot to display and process for normal humans ;)

like image 98
Preview Avatar answered Oct 11 '22 18:10

Preview