Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replenishment of element queue or backup element queue can be performed for the same element #10944

Open
dSalieri opened this issue Jan 24, 2025 · 0 comments
Labels
topic: custom elements Relates to custom elements (as defined in DOM and HTML)

Comments

@dSalieri
Copy link

dSalieri commented Jan 24, 2025

What is the issue with the HTML Standard?

I noticed that the enqueue a custom element callback reaction algorithm has a problem.

The gist: For the same element, step 6 can be performed multiple times, which will lead to a growing element queue or backup element queue, which will be filled with the same element, which is probably not what the spec wanted.

  1. Enqueue an element on the appropriate element queue given element.

When is this possible?

This is possible when the HTML parser creates a custom element with attributes that are observed (look at the create an element for a token algorithm in the step 10).

For example:

<script>
customElements.define("a-element", class extends HTMLElement {
    static get observedAttributes() {
        return ["a","b","c"];
    }
    attributeChangedCallback(...args){
        console.log(this, args[0]);
    }
});
</script>
<a-element a b c></a-element>

That is, the situation after adding attributes to the a-element element will be as follows:

Image

This happens because the element is added to two queues:

  1. Add a new callback reaction to element's custom element reaction queue, with callback function callback and arguments args.
  2. Enqueue an element on the appropriate element queue given element.

As a result, when the invoke custom element reactions algorithm is called, the reactions for the first element will be executed first (they are removed from the queue before execution), and there will simply be no reactions left for the rest elements, since all elements in the element queue are the same element.

This is what it looks like after the reactions are executed for the first element in the element queue (it has already been popped of the queue):


We can also consider the case where customElements.define is called for a-element, which calls upgrade reaction.

Example:

<a-element a b c></a-element>
<script>
customElements.define("a-element", class extends HTMLElement {
    static get observedAttributes() {
        return ["a","b","c"];
    }
    attributeChangedCallback(...args){
        console.log(this, args[0]);
    }
    connectedCallback(){
        console.log(this, "connectedCallback")
    }
});
</script>

When the time comes to execute the invoke custom element reactions algorithm, there will be only one reaction and it is upgrade reaction.

It looks like this:

By running this reaction we will run the upgrade an element algorithm (in this case the custom element reactions stack will be empty), which will set several reactions related to attributes and one related to connecting the element to the DOM.

It is also worth noting that the queue was replenished when there was an empty custom element reactions stack, which means that when we executed the enqueue an element on the appropriate element queue algorithm, we replenished the backup element queue for each reaction, and also scheduled one microtask (due to the set flag processing the backup element queue).

It looks like this:

Image

But we perform these reactions without leaving the invoke custom element reactions algorithm, due to the replenishment of the custom element reaction queue.

When the moment comes to execute our microtask to perform reactions for elements, it will do nothing, it will essentially be an empty call. Since all reactions for the element were called in the invoke custom element reactions algorithm for the element queue earlier.

What we have at the time of microtask execution:


As a result, we have a logic where element queue or backup element queue can add the same element, which pollutes the queue and creates extra work.

@domenic @annevk what do you think?

@domfarolino domfarolino added the topic: custom elements Relates to custom elements (as defined in DOM and HTML) label Jan 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: custom elements Relates to custom elements (as defined in DOM and HTML)
Development

No branches or pull requests

2 participants