Open wycats opened 8 years ago
@wycats To be specific, one thing that I'm really interested in, which this proposal does not cover, is event handling and I could really use your input on that if you have any thoughts.
@Gozala what's the easiest way to get in touch?
@wycats I've being noticing you at MozPDX fairly often, maybe next time you're there we can chat ? Alternatively IRC, you can find me as @gozala on both freenode and moz.
I looked into the concerns around NodeToken
being an integer (or number). For the DOMTreeConstruction
idea it can be an integer. The integers get returned as you use DOMTreeConstruction
. The moment you turn those integers into nodes using getNode()
, there's a reference to DOMTreeConstruction
available and any lookup only happens within that object. An implementation could store a map of integers to nodes on DOMTreeConstruction
the moment nodes are created as part of insertTreeBefore()
. As these integers are therefore entirely self-contained, this even paves the path toward DOMTreeConstruction
being serializable and network-transferable. To ensure we don't have to keep that map alive forever we could deterministically empty it by .then()
'ing the returned promise from insertTreeBefore()
. Those details can be fiddled with, this just shows it's viable.
DOMChangeList
is trickier as the integers can also represent nodes in an existing tree (via getToken()
, which is listed under DOMTreeConstruction
in OP, but is not part of it as no method takes a NodeToken
there), in a different thread. That means the integers for DOMChangeList
need to be unique within an agent cluster and are probably not suitable for network-transfer, ever. It also means they need to be long-lived as they need to be able to transfer across threads. The fogeability problem I would address by when looking up the node corresponding to an integer, also ensuring that its node document is identical to the document upon which applyChanges()
was invoked. And as said before for any instructions that are incorrect we'd abort, leaving you with a potentially broken tree as we cannot do transactions (see upthread).
(Given the nature of integers in DOMChangeList
I suspect there would need to be some requirement for them to be random to avoid fingerprinting.)
So in conclusion I think both designs are viable.
I think it's worth pointing out this experimental library I just put together: https://github.com/AshleyScirra/via.js
This allows full access to all DOM APIs using Proxys. It effectively builds an internal list of DOM commands and posts them to the main thread to be carried out. It happens entirely in JS land. I think its main advantage over DOMChangeList is it allows you to use all APIs the same way you do in the DOM, rather than a limited tree-construction subset with its own API. For example you can do div.style.fontWeight = "bold"
from a worker, or make use of mainthread-only APIs like the Web Audio API from a worker. Also the performance is actually kind of reasonable (it's not as terrible as I thought it might be, at least).
The main problem is that it leaks memory. GC is not observable so it's not possible to identify when the placeholder Proxy objects on the worker get collected and drop their corresponding references on the main thread. I think this can be solved with a special WeakKey
object which still doesn't make GC observable: https://discourse.wicg.io/t/a-way-to-the-use-dom-in-a-web-worker/2483/2?u=ashleyscirra
If I read this proposal right, it sounds like this WeakKey idea is like NodeToken but generalised to represent any DOM object at all. This significantly broadens the use cases it covers. For example we want to move our entire HTML5 game engine in to a worker, but the lack of APIs like Web Audio is a much bigger problem than whether or not we can create nodes. Via.js lets you do both: build up lists of DOM commands, and access arbitrary APIs only present on the main thread.
Could I get some sort of status update on this concept in general? (Evolutions, meeting notes, etc.?) Haven't really heard or seen anything about it anywhere, either here or on the WICG discourse. (I'm not active on any of the W3C/WHATWG mailing lists, though.)
There's no active mailing list. There was a meeting at a Mozilla All Hands, but that wasn't really conclusive one way or another. The main problem here is lack of implementer interest.
I wrote a blog post that covers some of the options to better support implementing this entirely in a library: https://www.scirra.com/blog/ashley/38/why-javascript-needs-cross-heap-collection
@annevk Sorry, I meant any of the W3C/WHATWG mailing lists. (I edited my comment accordingly.)
Also, I'm not a huge fan of the API proposed - it's a bit too verbose and too much of a shotgun for something that's really just performing transactions on nodes. I'd personally prefer there was a way to just force browsers to batch something without having changes exposed to the main thread until the next animation frame, and a way to run changes in the layout pass to reduce the impact of style recalcs (which account for 90% of the perf issues with DOM frameworks).
It's not transactions. We cannot do transactions given iframe
and such. And also, your API doesn't work in workers, which is rather big part of the value proposition. If you still wish to pursue it, please do so in a distinct issue.
Okay. 👍
DOMChangeList
andDOMTreeConstruction
Motivation
There are three high-level motivations for this API:
Element
s andNode
s.A
NodeToken
is an opaque value that represents aNode
. It can be efficiently transferred from one worker to another.It serves two purposes:
Node
that already exists in another worker, and can serve as the starting point of a series of mutations expressed in aDOMChangeList
.Node
that was produced as part of the process of building aDOMChangeList
.Applying a Change
The intent of this API is to have these performance characteristics:
DOMTreeConstruction
orDOMChangeList
) significantly reduces GC-managed allocations compared to the current DOM APIs.If there is some reason that a concrete implementation of this design might not be able to accomplish these goals, it's almost certainly something we should discuss.
Details
DOMTreeConstruction
DOMChangeList
Example
Using the usual DOM API:
Using the ChangeList API:
FAQ
Is this actually faster?
The intent of this API is to create a low-level interface that is as close as possible to the underlying implementations. It attempts to avoid introducing new costs while reducing a number of paper-cuts that exist in today's usage.
cloneNode
show that skipping those wrappers provides a performance benefit, butcloneNode()
can't satisfy as many use-cases as this API.Isn't the real issue that people are interleaving DOM manipulation and layout?
That is certainly a major issue, and this API puts developers on the path to success by encouraging them to stage DOM manipulation work separately from APIs that can trigger painting or layout.
Because the API guarantees that no user script can interleave during the application of changes, there is no way to "mess up" and trigger an immediate flush of any deferred work.
Unresolved Questions
ClassList
and thestyle
property through this API? It may be difficult to represent these kinds of changes with the operations already proposed (since this API does not allow direct imperative access to the DOM), and a few additional APIs probably wouldn't do damage to the constraints.