W3C home > Mailing lists > Public > public-webapps@w3.org > January to March 2014

Re: Why can't we just use constructor instead of createdCallback?

From: Ryosuke Niwa <rniwa@apple.com>
Date: Tue, 18 Feb 2014 14:12:50 -0800
Cc: Jonas Sicking <jonas@sicking.cc>, Boris Zbarsky <bzbarsky@mit.edu>, Erik Arvidsson <arv@chromium.org>, WebApps WG <public-webapps@w3.org>, Edward O'Connor <eoconnor@apple.com>, William Chen <wchen@mozilla.com>
Message-id: <C46D792C-A9A1-4BEF-A7A8-EDE32CE5740F@apple.com>
To: Dimitri Glazkov <dglazkov@google.com>
On Feb 18, 2014, at 10:35 AM, Dimitri Glazkov <dglazkov@google.com> wrote:
> On Fri, Feb 14, 2014 at 3:58 PM, Jonas Sicking <jonas@sicking.cc> wrote:
> What I mean is that for nodes that doesn't have a constructor, and
> whose parent doesn't have a constructor, no need to add them to the
> above arrays. Just insert them into their parent. That means that when
> that the constructor of an element runs, the element doesn't have any
> parents or children.
> So no need to hide parents or children anywhere.
> Okay, let me see if I got this right. The list is effectively a serialized representation of a document subtree. The parent + order in the list provides all the necessary information. We use this list to separate tree construction into two stages: one before custom element constructors are called, and one after.
> In cases when the custom element is just a like button widget (a leaf in the tree), the list is short and just contains the widgets.
> In cases like "<body><my-app><div> ... the entire doc tree ... </my-app></body>", the list contains the entire subtree of <my-app>, which is effectively the document.
> In cases like "<div><my-bar>..</my-bar><span>...</span> ... more siblings ... </div>", the list will contain at least all siblings of <my-bar>, because they can't be inserted into tree until after <my-bar>'s constructor runs.
> When run, the constructors are free to explore the partially-completed tree, which enables interesting hacks like this:
> in document:
> <div id="a"><my-bar></my-bar>.... lots more markup...
> in my-bar constructor:
> var myFutureParent = document.querySelector("#a");
> // redirect tree construction to resume at a new point.
> document.body.appendChild(myFutureParent);
> Or, in my-bar constructor:
> var myFutureParent = document.querySelector("#a");
> var iframe = document.body.appendChild(document.createElement("iframe"));
> // teleport the tree into another frame
> iframe.contentDocument.body.appendChild(myFutureParent);

You can already do this in a regular script element so this isn't a new issue custom element's constructor is introducing.

> The thing that really bothers me is that this approach is contradicting itself. We go to into pretty elaborate lengths to enable running constructors during parsing, but the key performance lesson developers will immediately learn is to avoid constructors on custom elements, because they will trigger the two-phase code path during parsing. Here's a thing that you can use, but you probably don't want to ever use it.

Have you tried implementing this and found that you can't implement it efficiently?  Could you quantify the runtime or memory cost?

> Here's an alternative proposal:
> 1) The Web developers are already aware of the fact that you can create new instances of JS objects without running their constructors with Object.create
> 2) Let's make sure that when they call constructors directly (as in var b = new MyB(arg1,arg2);), the constructor is actually called.
> 3) When the parser instantiates the element, it does the equivalent of Object.create, so no constructor is called.

I don't see why we want to make the edge case like the one you described above prevent us from making common cases easy to use and understand.

Just call constructor whenever a custom element is created.  If you're doing weird stuff in constructor, then weird things happen.

- R. Niwa

Received on Tuesday, 18 February 2014 22:12:58 UTC

This archive was generated by hypermail 2.4.0 : Friday, 17 January 2020 18:14:22 UTC