Re: Custom Elements: "createdCallback" & cloning

On Thu, Jul 2, 2015 at 4:05 PM, Anne van Kesteren <annevk@annevk.nl> wrote:

> In the interest of moving forward I tried to more seriously consider
> Dmitry's approach. Based on es-discussion discussion
> https://esdiscuss.org/topic/will-any-new-features-be-tied-to-constructors
> it seems likely new JavaScript features (such as private state) will
> be tied to object creation. This makes the prototype-swizzling design
> even less appealing, in my opinion.
>

Ironically this is a minor reason that Chromium preferred prototype
swizzling to "blessing" author-provided constructors:

When allocating JavaScript objects to wrap DOM objects ("wrappers"),
Chromium adds extra internal space to hold the address of the corresponding
C++ object. (V8 calls this "extra internal space" mechanism an "Internal
Field"
<https://code.google.com/p/chromium/codesearch#chromium/src/v8/include/v8.h&q=v8.h%20include/v&sq=package:chromium&type=cs&l=4660>.)
This is efficient (the space is accessed by offset; they don't have names
like properties do) and private (this mechanism is ancient--it predates
symbols--and is inaccessible to JavaScript because the space has no name
and is separate to how properties are stored.)

Because Custom Elements did not change how wrappers were allocated, Custom
Elements wrappers in Chromium continue to have the necessary extra storage
space. Because the Custom Element constructor was controlled by the user
agent, we could ensure that it used the same mechanism for allocating
wrappers.

We can't do that with a user-provided constructor, because V8 has already
allocated the object (for "this") by the time the constructor starts to
run. Any solution in this space may force Chromium to allocate an
additional object with the extra space. This may not be a disaster because,
first, generational GC makes allocating lots of short-lived objects
relatively cheap; and second, like Objective-C, JavaScript allows
constructors to return a different object (and my understanding is that
doing this in an ES6 constructor effectively sets "this".) But it is a bit
gross.

Around summer 2012? 2013? I experimented with using a Symbol-like thing
(which V8 calls Hidden Fields) to store the pointer to the C++ object on
Custom Element wrappers in Chromium. (So those wrappers had a different
shape to most element wrappers.) We felt this design was not feasible
because it was slower to access, made the objects larger, and complicated
Chromium's DOM bindings which now needed to fall back to checking for this
property.

I think the most important question here, though, is not constructors or
prototype swizzling. It's whether elements created before a definition is
available get enlivened with the definition when it is available. I don't
like prototype swizzling, but I do like what it lets us do:

- Progressive Enhancement. The author can write more things in markup and
present them while loading definitions asynchronously. Unlike progressive
enhancement by finding and replacing nodes in the tree, prototype swizzling
means that the author is free to detach a subtree, do a setTimeout, and
reattach it without worrying whether the definition was registered in the
interim.

- Fewer (no?) complications with parsing and cloning. Prototype swizzling
makes it possible to decouple constructing the tree, allocating the
wrapper, and running Custom Element initialization. For example, if you
have a Custom Element in Chromium that does not have a createdCallback, we
don't actually allocate its wrapper until it's touched (like any Element.)
But it would not be possible to distinguish whether a user-provided
constructor is trivial and needs "this."

It's a tradeoff. There are definite disadvantages to the current
specification; prototype swizzling is one of them. Not sure if that
background is useful...


> Meanwhile, I have not made much progress on the cloning question. As
> Domenic pointed out, that would also either require
> prototype-swizzling or invoking the constructor, there's not really a
> third way. I guess for that to work cloneNode() and various editing
> operations would have to become resilient against JavaScript executing
> in the middle of them,


Could you share a list of things that use the cloning algorithm?


> something that has caused (is causing?) us a
> ton of headaches with mutation events. (Or the alternative, have some
> kind of mode switch for the DOM which is similarly a large
> undertaking.)
>

What do you mean by mode switch?


> Not sure what to do now :-/
>
>
> --
> https://annevankesteren.nl/
>
>

Received on Friday, 10 July 2015 08:11:33 UTC