VDOM on the Server - Problems?

I’ve been looking at the possibility of implementing a server-side VDOM (Virtual Dom, like Reactjs, Vuejs, Snabbdom and onthers). The problem I see with this is the high latency of the updates, and the way it interacts with input components. Suppose you have a VDOM that returns the following (using vue-style templates):

Enter your name: <input v-model="name"></input>
<br/>
<span>Hello {{ name }}!</span>

The UI should be updated as the user types (probably debounding events, but that doesn’t change the main point).

Suppose the user types a “My Name”. The event is sent to the server, which sends the minimum delta so that the browser’s DOM is changed. But suppose now that before receiving the update, the user types “Another Name”. This can happen because latency between client and server can be arbitrarily high…

You’ll have something like this:

  1. User requests a page. The server sends a DOM with name = ""
  2. User types “My name”. The server receives an event. The server sends a new DOM with name = "My Name"
  3. The user types “Another Name”
  4. The user receives a new DOM with name = "My Name", which overwrites the text in the input component. This is a very surprising UI change
  5. The server receives name = "Another Name"
  6. The UI changes back to the previous version.

I don’t think how one can avoid this. There is a serious mismatch that will keep the client and server permanently out of sync. Althout I’ve often felt that a VDOM was superior to the approach taken by Drab (which has the concept of living assigns, and instead of re-rendering everything and diffing the result updates parts of templates that correspond to specific mutations), now I’m not so sure, because of the way the network latency messes with the input components’ updates…

I’m not aware of any widely used server-side VDOM, so I don’t know if anyone has managed to find a way around this limitation.

Why do you want to handle user input live on the server? The only common case I can see using something like that would be live search results.

3 Likes

What about this:

C: {ref: "xz723", name: "My Name"}
C: {ref: "v44ns", name: "Another Name"}
S: {ref: "xz723", domNode({name: "My Name"})}
C: I’m ignoring that, my ref is "v44ns"

Or even

C: I’m ignoring that, did you see what I just sent you? {ref: "v44ns", name: "Another Name"}

I can think of other cases, such as realtime validation of form parameters, password strength checking, etc.

But these limitations apply even without “realtime” handling of keystrokes. Just suppose you type the name, press a save button and then type another name before you receive the reply from the server.

The input componenet will still revert to the previous state for a while (and then revert back)

This really sounds more like something RxJS is used for:

  • Whenever input changes, reset client side UI rendering to reflect that data has not been validated.
  • As input state changes, dispatch validation requests to the server.
  • Upon validation response the client verifies that the validated data matches the current input data (client based correlation id would be faster) - and only when it matches, the UI renders client side with validation errors or success.

Ultimately a server-based VDOM is just way too chatty - too many, too finely grained updates need to be exchanged between the server and browser.

1 Like

That might actually work. It sounds like a very limited form of Operational Transformation that might be useful in practice

Drab is already halfway to that, it creates a pre-processed virtual dom for fast updates later. ^.^;

However, as for the latency Drab generally just disables what is being waited on until it completes (configurable of course).

1 Like

Drab seems to use “mutation watchers” which try very hard to rerender only the UI parts that depend on values that have changed.

This is very different from a VDOM in reactjs or the elm architecture in which the engine renders a new dom and diffs t against the previous one.

I don’t think you can get from Drab to a VDOM incrementally, because those are very different concepts.

Those watchers are how a vdom diff works anyway (it’s certainly how my super-fast-yet-not-optimized bucklescript-tea vdom diff’s anyway). There are lots of ways to implement vdom’s, React’s broken way is not the only way. ^.^

I think that the problem here is latency alone, not chatinness. You can be as chatty as you want as long as you can output a DOM diff between two user events (in the limit, between 2 keystrokes). That guarantees that you’l never rever input components to the last update (because you’ll be setting the component’s input yo the value it already has).

That’s doable with local Javascript, but it’s not doable over the network.

Does your approach with mutation watchers work with general render functions?

Mutation watchers in as far as checking for changes on the vdom, though my current dev iteration of bs-tea uses kind of ‘pipes’ to mark areas instead. But currently I’m not sure you mean by ‘general render function’? Do you mean calling something else to return a vdom from inside the vdom? If so then the lazy construct can do that. Do you mean rendering, say, a javascript owned element? Then not yet but that’s planned as the CustomNode, however I find webcomponents better for that anyway and should be used and work fine in the current system (as does bucklescript-tea work perfectly inside a web component, I find the whole concept of chaning javascript calls to build the DOM tree a horrible misdesign that a lot of people do for who knows what reasons, webcomponents are superior).

I’m yalking about having something like:

inner_vdom_fragment = f(state)

Is this what you consider a bad design decision?

:icon_question:

Given that latency in the real world is always greater-than-zero, chattiness will always create problems (prefer fewer messages with larger payloads (i.e. more coarse grained messages)).

source

3 Likes

Chatiness as in “sends data over the network” is a problem, of course. Because of network latency. I thought you were referring to the amount of data trabsmitted over the network, which is not a very important variable (as long as it’s greater than zero!)… We are actually saying the same thing in different ways.

In my Tea library parlance would that be something like where f is a function call typed like model -> 'msg vdom or what is it all?

Which is why I love that the BEAM builds timeouts into everything. ^.^

Hmm, I am not aware of it, but maybe because of the terminology.

1 Like

Yeah I’m curious about that as well, mutation watchers in javascript was turned down by the spec so they don’t exist anymore (and hard to emulate reliably, look at all the pain that polymer had to emulate it).

1 Like

I’ve never heard about mutation watchers before, this is why I doubt I am using it in Drab. But it always may be an issue with a terminology.

I am afraid Drab is not so sophisticated. It uses something I may call “naive direct updaters” than “mutation watchers” :slight_smile:

2 Likes