Skip to content
This repository has been archived by the owner on May 29, 2019. It is now read-only.

Several questions about the "Initialisation order" section #1456

Closed
mercmobily opened this issue Dec 5, 2015 · 15 comments
Closed

Several questions about the "Initialisation order" section #1456

mercmobily opened this issue Dec 5, 2015 · 15 comments

Comments

@mercmobily
Copy link

I have a few questions regarding the Initialisation order section.

The element’s basic initialization order is:
created callback
local DOM initialized
ready callback
factoryImpl callback
attached callback

  • What do you mean by "local DOM initialised"? Is it when various helpers (dom-repeat, etc) are set? Or all elements in the local DOM are ready()ed? Or... what do you mean exactly?

Note that the initialization order may vary depending on whether or not the browser includes native support for web components.

Here, it looks like the calls above may be called in a different order. However, the next sentence:

In particular, there are no guarantees with regard to initialization timing between sibling elements or between parents and light DOM children.

Seems to focus on initialisation timing among parent/siblings, rather than initialisation order within an element. And it's talking specifically about light DOM...

The document then continues:

The created callback is always called before ready.
The ready callback is always called before attached.

So, the order created -> ready -> attached is always observed... whereas factoryImpl and local DOM initialisation may happen anytime?

The ready callback is called on any local DOM children before it’s called on the host element.

Does that mean that ready() is called on the host element before any local DOM children, but you cannot trust the light DOM children's ready() to be called after the host element's ready()?

Finally, the doc says:

For accessing sibling elements when an element initializes, you can call async from inside the attached callback:

Does that mean siblings within the light DOM? Or local DOM? Or either?

OK, I must admit I am totally confused by this section. Help :D

The main points are:

  • It's not clear what you mean by "local DOM initialisation"
  • not clear what you mean by "initialization order may vary "
  • I think the main issue is with the order of initialisation in *light DOM widgets, whereas you can expect local DOM children to get ready() before its parent...

I would do the following:

  • Specify that the initialisation order is for the widget itself, and it's always the same
  • Specify clearly that there may be timing issues with initialisation timing between parents and siblings
  • Focus on what the issue is -- that is, siblings and light DOM children maybe initialised (or maybe ready..?) in any order.

I am sorry, this ticket is confusing because I really haven't managed to make heads or tails of what exactly the issues are.

In the Migration guide, I read:

"A more complete solution is in progress. In the meantime, if you are using domReady in 1.0 you can replace it by using the async method inside your attached callback:"

Is there a ticket where this is being tackled? I'd love to have a look.

Sorry, as you can see I am going through the Polymer documentation, and... I guess that's what you get when you get somebody ever so slightly obsessive to go through things...

(Plus, it's not clear how an element would be able to know when all of its light DOM children are fully initialised!)

@arthurevans
Copy link

No apologies necessary, keep up the great feedback.

The section is confusing partly because there are only a few guarantees we can give, and many mysteries. But your feedback is spot-on and we can definitely clarify many of these points.

Broadly speaking, your interpretation is correct as I understand it.

For any given element, the order is as listed.

Local DOM init means, "local DOM children are created, their property values are set as specified in the template, and ready() has been called on them." In essence, it means, "the stuff we do before calling ready," so maybe we can just be clearer about what that is and drop it from this list.

  • Caveat 1: dom-repeat and dom-if create dom asynchronously based on the property values you set on them (if, items, etc.). Thee elements can't start rendering (i.e., creating DOM) until ready has been called on them, so this DOM isn't going to be complete when ready is called on the parent element.
  • Caveat 2: We guarantee that local DOM child ready is called before parent ready, but we can't guarantee the relative ordering of local DOM child attached and parent attached. This is one place where native and polyfill behavior is different.

As for light children, there are no guarantees at all, although broadly speaking you would expect them to be ready in document order, which means they'd be initialized after their parents. Usually. Of course, the user can add light children at any time.

Fortunately, you can now use observeNodes if you need to track light DOM nodes. We should add a cross-reference here because it's a common question with regard to lifecycle.

@mercmobily
Copy link
Author

When you say:

Caveat 1: dom-repeat and dom-if create dom asynchronously based on the property values you set on them (if, items, etc.). These elements can't start rendering (i.e., creating DOM) until ready has been called on them, so this DOM isn't going to be complete when ready is called on the parent element.

Here, what do you mean by "These", and what do you mean by "them"?
So, this means that an element will have ready() called before the dom-repeat has actually gone through everything. Right?

We guarantee that local DOM child ready is called before parent ready,

(Except for elements created in a dom-repeat statement!)

but we can't guarantee the relative ordering of local DOM child attached and parent attached. This is one place where native and polyfill behavior is different.

Meaning that the an element E with children elements C1 C2 C3 might be attached to its parent P before C1, C2 and C3 are attached to E itself?

@arthurevans
Copy link

For #1, by "these elements" and "them" I mean "dom-if or dom-repeat elements".

The thing to remember is that the dom-repeat isn't some kind of special statement, it's a custom element. When you set an items value on it, it responds by asynchronously creating instances of its template contents. When you use it inside an element's template, the parent element instantiates a dom-repeat element, sets its items property, and calls ready on it--at that point, the dom-repeat starts its own (async) work, while the parent element goes on getting ready.

On the last comment--I'm not sure whether the actual attachment happens in a different order, or just the attached callback. We actually defer firing attached on any given element until after it's ready. So, there may be a period where the browser thinks the element is attached, but the element hasn't had its attached callback called yet.

@mercmobily
Copy link
Author

And about this one:

As for light children, there are no guarantees at all, although broadly speaking you would expect them to be ready in document order, which means they'd be initialized after their parents. Usually. Of course, the user can add light children at any time.

So if I have something like that:

<avatar-list>
  <my-photo class="photo" src="one.jpg">First photo</my-photo>
  <my-photo class="photo" sec="two.jpg">Second photo</my-photo>
</avatar-list>

And avatar-list has <content> element with selector on .photo somewhere, <avatar-list> is likely to be ready() before the various <my-photo> elements are ready()?

@arthurevans
Copy link

Correct.

@mercmobily
Copy link
Author

My attempt to amend the existing documentation. I tried to integrate everything we discussed, so that (hopefully) nobody wonders the same thing.

I divided the issue in three different parts; I feel that this makes things clearer. I also made a distinction between initialisation order and initialisation timing.

I would love to also have a section here that explains the practical implications of this. When does it really matter than a child's ready() hasn't yet been called?

(Note that I tried my best to use american spellings, but UK/Aussie slip-ups might have happened :D (I'm Australian)


Initialization order and timing {#initialization-order}

The element's basic initialization order for a given element is:

  • created callback
  • local DOM initialized (This means that local DOM children are created, their property values are set as specified in the template, and ready() has been called on them)
  • ready callback
  • factoryImpl callback
  • attached callback

Note that while the life cycle callbacks listed above will be called in the described order for any given element, the initialization timing between elements may vary depending on whether or not the
browser includes native support for web components.

Initialization timing for light DOM children

As far as initialization timing of light DOM children there are no guarantees at all, although broadly speaking you would expect them to be ready in document order, which means they'd be usually initialized after their parents. Of course, the user can add light children at any time.

For example if you have something like this:

<avatar-list>
  <my-photo class="photo" src="one.jpg">First photo</my-photo>
  <my-photo class="photo" src="two.jpg">Second photo</my-photo>
</avatar-list>

And avatar-list has a <content> element with selector on .photo, <avatar-list> is likely to be ready() before the various <my-photo> elements are ready().

Initialization timing for local DOM children

Local DOM children are created, their property values are set as specified in the template, and ready is called on them before their parent's ready is.

There are two caveats:

  • dom-repeat and dom-if create DOM asynchronously based on the property values set on them (e.g. if, items, etc.). Note that dom-repeat isn't a "special" statement: it's a normal custom element. When you set an items value on it, it responds by asynchronously creating instances of its template contents. When you use it inside an element's template, the parent element instantiates a dom-repeat element, sets its items property, and calls ready on it -- at that point, the dom-repeat starts its own (async) work, while the parent element goes on getting ready.
  • Polymer guarantees that local DOM children have their ready callback called before their parent's; however, it cannot guarantee the same thing for the attached callback. This is one place where native and polyfill behavior is different.

Initialization timing for siblings

There are no guarantees with regard to initialization timing between sibling elements.

This means that siblings may become ready in any order.

For accessing sibling elements when an element initializes, you can call async from inside
the attached callback:

attached: function() {
   this.async(function() {
      // access sibling or parent elements here
   });
}

I hope this helps...

Merc.

@mercmobily
Copy link
Author

BTW I realise what I wrote is longer than the original version. As usual, if you think it's not up to standard or not usable, 10000% NOT hard feelings!

@arthurevans
Copy link

Thanks Merc. I think I can use something like that, but I'd have to massage to fit the doc site style.

If you're interested, you can open a PR and I'll walk you through the edits. Or I can do it.

@BLamy
Copy link

BLamy commented Dec 23, 2015

👍 This new explanation actually helped me quite a bit.

You may want to change

Local DOM children are created, their property values are set as specified in the template, and ready is called on them before their parent's ready is.

to something which gives a brief ELI5 explanation of what local dom is, and then get into how it behaves.

Local DOM refers to the children which are located in the template inside of your dom-module. Local DOM children are created, their property values are set, and ready is called on them before ready is called on their parent.

@robdodson
Copy link
Contributor

💯 this thread is a great read :)

@mercmobily
Copy link
Author

Sorry for answering so late. My computer actually broke, and had to real with some interesting disaster recovery...
I cloned the "docs" repo, and managed to serve it locally. Shall I just fix the explanation I wrote (I have already found a couple of mistakes), patch the relevant file, and summit a PR?
(If you think my explanation deserves to be on the docs -- if not, all good, honestly)

@arthurevans
Copy link

Hi @mercmobily! Sorry to hear about your computer.

I think the general structure is good, we need to make the language a little less chatty, but that's a detail. If you're up for it, please go ahead with the PR!

I'm off work until the new year, so if you don't hear from me right away... I'm not neglecting you, but this eggnog's not going to drink itself.

@mercmobily
Copy link
Author

Hi,

OK will do!

Merc.

On 24 December 2015 at 04:17, Arthur Evans [email protected] wrote:

Hi @mercmobily https://github.com/mercmobily! Sorry to hear about your
computer.

I think the general structure is good, we need to make the language a
little less chatty, but that's a detail. If you're up for it, please go
ahead with the PR!

I'm off work until the new year, so if you don't hear from me right
away... I'm not neglecting you, but this eggnog's not going to drink itself.


Reply to this email directly or view it on GitHub
#1456 (comment).

@mercmobily
Copy link
Author

Well I did: #1479 I guess this ticked could/should be closed?

@dwsmorris
Copy link

dwsmorris commented May 13, 2016

Hi,

I'm looking for a way to ensure that the attached callback on child elements are called before the attached callback on the parent.
I have initialization logic in 'attached' that requires that this be true.
A related suggestion above for using async does actually work, in that, if you wrap the parent's attached code in async, it is called after the childs.
However, this only works for components two levels deep. If I have a component three levels deep, I can't guarantee the order in which the attached callbacks are called by using async.
Is there a way to do this?
I can't use ready as I need to be able to reference the local dom.

Thanks,
Darryl


update:
So, I found a way to do this in "ready" which has order guaranteed (probably doing initialization-sensitive work in attached was wrong anyway).
I can fish out the correct nodes in "ready" using this.$ (rather than document.querySelector that I was doing in "attached"). I now need to id the nodes but that's no biggie.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants