Hacker News new | ask | show | jobs
by riskable 804 days ago
It's never that simple. In web applications there's always these types of states:

    * States that the client needs to keep track of
    * States that the server needs to keep track of
Then on top of those there's two more kinds of states that overlap but they're not quite the same thing:

    * States that only need to exist in memory (i.e. transient)
    * States that need to persist between sessions
There's a seemingly infinite number of ways to manage these things and because "there's no correct way to do anything in JavaScript" you either use a framework's chosen way to deal with them or you do it on an ad-hoc basis (aka "chaos" haha).

In the last sophisticated SPA I wrote I had it perform a sync whenever the client loaded the page. Every local state or asset had a datetime-based hash associated with it and if it didn't match what was on the server the server would send down an updated version (of whatever that thing was; whether it be simple variables, a huge JSON object, or whole images/audio blobs).

Whenever the client did something that required a change in state on the server it would send an update of that state over a WebSocket (99% of the app was WebSocket stuff). I didn't use any sort of sophisticated framework or pattern: If I was writing the code and thought, "the server needs to keep track of this" I'd have it send a message to the server with the new state and it would be up to the server whether or not that state should be synchronized on page load.

IMHO, that's about as simple a mechanism as you can get for managing this sort of thing. WebSockets are a godsend for managing state.

1 comments

Interesting. What kind of app was it? How did you decide whether the server needed to keep track it? I’m assuming that was predetermined? What about new requirements, which would need to be tracked by the server? Could the app deal with this dynamically without code changes?
It was Gate One: https://github.com/liftoff/GateOne

(Note: Company no longer exists so it is unmaintained, fork at will =)

It's been so long since I've looked at the code but I did write excellent documentation, most of which is generated from docstrings. Example:

https://github.com/liftoff/GateOne/blob/master/gateone/core/...

You can read the documentation here:

https://liftoff.github.io/GateOne/

If you look at the bookmarks plugin you can see an example of how I performed this style of client<->server synchronization using an Update Sequence Number (USN):

https://github.com/liftoff/GateOne/blob/6ae1d01f7fe21e2703bd...

After the web client connects to the websocket all the plugin's `init()` methods are called and the bookmarks plugin's javascript file calls `userLoginSync()`:

https://github.com/liftoff/GateOne/blob/6ae1d01f7fe21e2703bd...

It sends the current USN (which is retrieved from `localStorage`) to the server (the routing is quite sophisticated... Just know that the message ends up going to the correct function =) and if it's different from the USN on the server the server will send an updated list of bookmarks to the client at which point the client will take care of that via its own handler:

https://github.com/liftoff/GateOne/blob/6ae1d01f7fe21e2703bd...

If you examine the bookmarks.js from top to bottom (it's not THAT long) you should get the gist of where and how various states are stored. That plugin mostly deals with stuff in `localStorage` but if you poke around in Gate One you'll see vastly more sophisticated state synchronization and state update routines at work.