Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save colingourlay/0f82aa1c345bd30ab810 to your computer and use it in GitHub Desktop.
Save colingourlay/0f82aa1c345bd30ab810 to your computer and use it in GitHub Desktop.
A discussion of the challenges I anticipate we will face creating a widely useful system based on a virtual DOM running in a web worker

I have been watching the current discussions about running a virtual DOM in a web worker with a great deal of interest. In 2011, I built a research project, Treehouse (USENIX Talk (DOMTRIS demo at 20:25), paper), which ran a hacked-up version of jsdom in a worker. My goal was fine-grained containment of untrusted scripts, while still providing access to browser APIs that existing code expected.

Treehouse achieved a small amount of influence in academic circles, but it had problems and was ultimately unsuccessful. Virtual DOMs were not a widespread or well-understood idea at the time, so the advantages of running one in a worker were difficult to communicate.

I'm very excited that the idea has found new traction. I think it promises huge performance and security wins. With that said, it's quite a bit trickier to get right than it appears on the surface. In particular, building a worker VDOM system that will work for a large set of web content is a much harder engineering problem than building one that works for a single app.

Challenges

Correctness

Here are a few ways that a worker VDOM system may get into an inconsistent state or behave in ways that surprise the user.

Synchronous interfaces and side effects

An important challenge is that some browser APIs are synchronous, but the postMessage interface is asynchronous. Fortunately, the virtual DOM abstracts away the largest synchronous API surface: the DOM. However, some tricky synchronous bits remain.

Synchronous APIs

Other than the DOM itself, synchronous APIs are fortunately relatively rare. Those that are present can usually be virtualized. Others, like window.prompt cannot.

These can probably be safely ignored.

Event capture and cancellation

There was a good twitter discussion about this. The crux is that event cancellation is synchronous in the parent page, but the application's event handlers should run in the worker, and will thus not have an opportunity to cancel the event.

The proposed solution is to cancel all events at the root of the virtual DOM. This will likely work, though I fear it will have tricky semantics for things like clicks on links.

Difficult and hidden state

There is a surprising amount of state in the browser that is hidden or difficult to monitor for changes. This state will need to be synchronized to the worker.

Input values

Changes to the value of form inputs do not trigger DOM attribute changes (though they do fire input events in modern browsers). So, how does the worker's virtual DOM get updated with the latest input values? Dispatching only input events the app listens for is insufficient, as the app may examine the value of an input that it is not listening to.

I believe it will be necessary to stream input events for every input element that is in the worker's VDOM. It may be necessary to stream key events as well.

Computed values

This is a tough one. How will the worker's VDOM know what to return if the app ask for something like an element's style.color. Similarly, what will it return if the app asks for an element's scrollHeight?

I believe this will require apps to use some new asynchronous interface instead of the usual DOM APIs.

Concurrency

This is perhaps the hardest challenge. When I designed Treehouse, I thought that I avoided the problem of handling concurrent access to VDOM nodes by requiring that a particular DOM node appear in at most one VDOM. Unfortunately, James Mickens pointed out in Pivot that I missed an additional writer: the user.

It's possible for the user to interact with a DOM that is out of sync with the VDOM in the worker. How the app would handle a UI event in this situation is unclear. I emailed with Brian Ford about this, in regards to Angular 2's plans to support worker apps. He argued that limiting the capabilities of the app mitigates this concern. In the more general case, something like Operational Transforms may work.


I will flesh out the outline below sometime tomorrow.

Performance

  • High-thoughput events
    • Mouse movement
    • Scrolling
  • Latency-sensitive events
    • key events
    • mouse events
    • scrolling
    • onunload

Containment

  • CSS
  • event capture and bubbling

Developer experience

Debugging

DOM inspection

Profiling

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment